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 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_hub_configure PORTABLE C */
37 /* 6.1.11 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function calls the USBX stack to do a SET_CONFIGURATION to the */
45 /* HUB. Once the HUB is configured, its interface will be activated */
46 /* and all the endpoints enumerated (1 interrupt endpoint in the case */
47 /* of the HUB). */
48 /* */
49 /* INPUT */
50 /* */
51 /* hub Pointer to HUB */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* Completion Status */
56 /* */
57 /* CALLS */
58 /* */
59 /* _ux_host_stack_device_configuration_get Get device configuration */
60 /* _ux_host_stack_device_configuration_select */
61 /* Select device configuration */
62 /* _ux_host_stack_configuration_interface_get */
63 /* Get interface */
64 /* _ux_host_stack_transfer_request Process transfer request */
65 /* _ux_utility_memory_allocate Allocate memory block */
66 /* _ux_utility_memory_free Release memory block */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* HUB Class */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
77 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
78 /* optimized based on compile */
79 /* definitions, */
80 /* resulting in version 6.1 */
81 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
82 /* internal clean up, */
83 /* resulting in version 6.1.11 */
84 /* */
85 /**************************************************************************/
_ux_host_class_hub_configure(UX_HOST_CLASS_HUB * hub)86 UINT _ux_host_class_hub_configure(UX_HOST_CLASS_HUB *hub)
87 {
88
89 UINT status;
90 UX_CONFIGURATION *configuration;
91 UX_DEVICE *device;
92 UX_ENDPOINT *control_endpoint;
93 UCHAR *device_status_data;
94 UX_TRANSFER *transfer_request;
95 #if UX_MAX_DEVICES > 1
96 UX_DEVICE *parent_device;
97 #endif
98
99
100 /* A HUB normally has one configuration. So retrieve the 1st configuration
101 only. */
102 _ux_host_stack_device_configuration_get(hub -> ux_host_class_hub_device, 0, &configuration);
103
104 /* Get the device container for this configuration. */
105 device = configuration -> ux_configuration_device;
106
107 /* To find the true source of the HUB power source, we need to do a GET_STATUS of
108 the device. */
109 control_endpoint = &device -> ux_device_control_endpoint;
110 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
111
112 /* Allocate a buffer for the device status: 2 bytes. */
113 device_status_data = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 2);
114 if (device_status_data == UX_NULL)
115 return(UX_MEMORY_INSUFFICIENT);
116
117 /* Create a transfer_request for the GET_STATUS request, 2 bytes are returned. */
118 transfer_request -> ux_transfer_request_requested_length = 2;
119 transfer_request -> ux_transfer_request_data_pointer = device_status_data;
120 transfer_request -> ux_transfer_request_function = UX_GET_STATUS;
121 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
122 transfer_request -> ux_transfer_request_value = 0;
123 transfer_request -> ux_transfer_request_index = 0;
124
125 /* Send request to HCD layer. */
126 status = _ux_host_stack_transfer_request(transfer_request);
127
128 /* Check the status and the length of the data returned. */
129 if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == 2))
130 {
131
132 /* The data returned is good, now analyze power source. */
133 if (*device_status_data & UX_STATUS_DEVICE_SELF_POWERED)
134 device -> ux_device_power_source = UX_DEVICE_SELF_POWERED;
135 else
136 device -> ux_device_power_source = UX_DEVICE_BUS_POWERED;
137
138 /* Free the buffer resource now. */
139 _ux_utility_memory_free(device_status_data);
140 }
141 else
142 {
143
144 /* Free the buffer resource now. */
145 _ux_utility_memory_free(device_status_data);
146
147 /* Error trap. */
148 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_CONNECTION_INCOMPATIBLE);
149
150 /* If trace is enabled, insert this event into the trace buffer. */
151 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONNECTION_INCOMPATIBLE, hub, 0, 0, UX_TRACE_ERRORS, 0, 0)
152
153 /* Return an error. */
154 return(UX_CONNECTION_INCOMPATIBLE);
155 }
156
157 #if UX_MAX_DEVICES > 1
158 /* Check the HUB power source and check the parent power source for
159 incompatible connections. */
160 if (hub -> ux_host_class_hub_device -> ux_device_power_source == UX_DEVICE_BUS_POWERED)
161 {
162
163 /* Get the parent container for this device. */
164 parent_device = device -> ux_device_parent;
165
166 /* If the device is NULL, the parent is the root HUB and we don't have to worry
167 if the parent is not the root HUB, check for its power source. */
168 if ((parent_device != UX_NULL) && (parent_device -> ux_device_power_source == UX_DEVICE_BUS_POWERED))
169 {
170
171 /* Error trap. */
172 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_CONNECTION_INCOMPATIBLE);
173
174 /* If trace is enabled, insert this event into the trace buffer. */
175 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONNECTION_INCOMPATIBLE, hub, 0, 0, UX_TRACE_ERRORS, 0, 0)
176
177 return(UX_CONNECTION_INCOMPATIBLE);
178 }
179 }
180 #endif
181
182 /* We have the valid configuration. Ask the USBX stack to set this configuration. */
183 _ux_host_stack_device_configuration_select(configuration);
184
185 /* If the operation went well, the HUB default alternate setting for the HUB interface is
186 active and the interrupt endpoint is now enabled. We have to memorize the first interface
187 since the interrupt endpoint is hooked to it. */
188 status = _ux_host_stack_configuration_interface_get(configuration, 0, 0, &hub -> ux_host_class_hub_interface);
189
190 /* Return completion status. */
191 return(status);
192 }
193
194