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 UX_MAX_DEVICES > 1
33
34 #if defined(UX_HOST_STANDALONE)
35 UINT _ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB *hub, UCHAR *descriptor);
36 UINT
37 #else
38 static inline UINT
39 #endif
_ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB * hub,UCHAR * descriptor)40 _ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB *hub, UCHAR *descriptor)
41 {
42 UINT status = UX_SUCCESS;
43 ULONG tt_protocols; /* (bDeviceProtocol << 8) | bInterfaceProtocol */
44 ULONG port_index;
45
46 /* Parse the device descriptor and create the local descriptor. */
47 _ux_utility_descriptor_parse(descriptor, _ux_system_hub_descriptor_structure, UX_HUB_DESCRIPTOR_ENTRIES,
48 (UCHAR *) &hub -> ux_host_class_hub_descriptor);
49
50 /* Check the protocol used by the HUB. This will indicate if the HUB supports multiple TTs in high speed mode. */
51 tt_protocols = ((ULONG)hub -> ux_host_class_hub_device -> ux_device_descriptor.bDeviceProtocol << 8) |
52 hub -> ux_host_class_hub_interface -> ux_interface_descriptor.bInterfaceProtocol;
53 switch(tt_protocols)
54 {
55
56 /* 1. A hub operating at full-/low-speed has a device descriptor with a bDeviceProtocol field set to zero(0)
57 * and an interface descriptor with a bInterfaceProtocol field set to zero(0).
58 */
59 case (UX_HOST_CLASS_HUB_PROTOCOL_FS << 8):
60
61 /* In the case of full speed hub, there are no TTs to declare */
62 break;
63
64 /* 2. A hub that has a single TT must set the bDeviceProtocol field of the device descriptor to one(1) and
65 * the interface descriptor bInterfaceProtocol field set to 0.
66 * 3. A multiple TT hub must set the bDeviceProtocol field of the device descriptor to two (2).
67 * The first interface descriptor has the bInterfaceProtocol field set to one(1).
68 */
69 case (UX_HOST_CLASS_HUB_PROTOCOL_SINGLE_TT << 8): /* Fall through. */
70 case (UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT << 8) | UX_HOST_CLASS_HUB_PROTOCOL_SINGLE_TT:
71
72 /* Single TT hub or single TT interface. */
73 /* Check if current setting supports this Hub. */
74 if (hub -> ux_host_class_hub_descriptor.bNbPorts > UX_MAX_TT)
75 {
76
77 status = UX_TOO_MANY_HUB_PORTS;
78 break;
79 }
80
81 /* In a single TT state, all the downstream ports report to the same
82 TT and share the 1.1 USB segment bandwidth. This is a very crude
83 but working method, we simply set all the ports bits to the first
84 TT. */
85 hub -> ux_host_class_hub_device -> ux_device_hub_tt[0].ux_hub_tt_port_mapping = UX_TT_MASK;
86 hub -> ux_host_class_hub_device -> ux_device_hub_tt[0].ux_hub_tt_max_bandwidth = UX_TT_BANDWIDTH;
87 break;
88
89 /* 3. A multiple TT hub must set the bDeviceProtocol field of the device descriptor to two (2).
90 * The first interface descriptor has the bInterfaceProtocol field set to one(1).
91 * Such a hub also has a second interface descriptor where the bInterfaceProtocol is set to two(2).
92 */
93 case (UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT << 8) | UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT:
94
95 /* Multiple TTs. */
96 /* Check if current setting supports this Hub. */
97 if (hub -> ux_host_class_hub_descriptor.bNbPorts > UX_MAX_TT)
98 {
99
100 status = UX_TOO_MANY_HUB_PORTS;
101 break;
102 }
103
104 /* In the case of multiple TTs, each downstream port can sustain the USB 1.1
105 max bandwidth and therefore we allocate one TT per port with that bandwidth. */
106 for (port_index = 0; port_index < hub -> ux_host_class_hub_descriptor.bNbPorts; port_index++)
107 {
108
109 hub -> ux_host_class_hub_device -> ux_device_hub_tt[port_index].ux_hub_tt_port_mapping = (ULONG)(1 << port_index);
110 hub -> ux_host_class_hub_device -> ux_device_hub_tt[port_index].ux_hub_tt_max_bandwidth = UX_TT_BANDWIDTH;
111 }
112 break;
113
114 default: /* Invalid bDeviceProtocol and bInterfaceProtocol pair. */
115
116 /* We should never get here. In this case the protocol value of the HUB is illegal. */
117 status = UX_DESCRIPTOR_CORRUPTED;
118 }
119
120 /* Return status. */
121 return(status);
122 }
123 #endif
124
125
126 /**************************************************************************/
127 /* */
128 /* FUNCTION RELEASE */
129 /* */
130 /* _ux_host_class_hub_descriptor_get PORTABLE C */
131 /* 6.3.0 */
132 /* AUTHOR */
133 /* */
134 /* Chaoqiong Xiao, Microsoft Corporation */
135 /* */
136 /* DESCRIPTION */
137 /* */
138 /* This function obtains the HUB descriptor. This descriptor contains */
139 /* the number of downstream ports and the power characteristics of the */
140 /* HUB (self powered or bus powered). */
141 /* */
142 /* INPUT */
143 /* */
144 /* hub Pointer to HUB */
145 /* */
146 /* OUTPUT */
147 /* */
148 /* Completion Status */
149 /* */
150 /* CALLS */
151 /* */
152 /* _ux_host_stack_transfer_request Process transfer request */
153 /* _ux_utility_memory_allocate Allocate memory block */
154 /* _ux_utility_memory_free Release memory block */
155 /* _ux_utility_descriptor_parse Parse descriptor */
156 /* */
157 /* CALLED BY */
158 /* */
159 /* HUB Class */
160 /* */
161 /* RELEASE HISTORY */
162 /* */
163 /* DATE NAME DESCRIPTION */
164 /* */
165 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
166 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
167 /* optimized based on compile */
168 /* definitions, */
169 /* resulting in version 6.1 */
170 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
171 /* improved protocol handling, */
172 /* resulting in version 6.1.10 */
173 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
174 /* added standalone support, */
175 /* resulting in version 6.1.12 */
176 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
177 /* fixed compile warnings, */
178 /* resulting in version 6.3.0 */
179 /* */
180 /**************************************************************************/
_ux_host_class_hub_descriptor_get(UX_HOST_CLASS_HUB * hub)181 UINT _ux_host_class_hub_descriptor_get(UX_HOST_CLASS_HUB *hub)
182 {
183
184 UCHAR *descriptor;
185 UX_ENDPOINT *control_endpoint;
186 UX_TRANSFER *transfer_request;
187 UINT status;
188
189
190 /* We need to get the default control endpoint transfer request pointer. */
191 control_endpoint = &hub -> ux_host_class_hub_device -> ux_device_control_endpoint;
192 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
193
194 /* Need to allocate memory for the descriptor. */
195 descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HUB_DESCRIPTOR_LENGTH);
196 if (descriptor == UX_NULL)
197 return(UX_MEMORY_INSUFFICIENT);
198
199 /* Create a transfer request for the GET_DESCRIPTOR request. */
200 transfer_request -> ux_transfer_request_data_pointer = descriptor;
201 transfer_request -> ux_transfer_request_requested_length = UX_HUB_DESCRIPTOR_LENGTH;
202 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HUB_GET_DESCRIPTOR;
203 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE;
204 transfer_request -> ux_transfer_request_value = (UX_HUB_DESCRIPTOR_ITEM << 8);
205 transfer_request -> ux_transfer_request_index = 0;
206
207 #if defined(UX_HOST_STANDALONE)
208
209 /* Save allocated buffer pointer. */
210 hub -> ux_host_class_hub_allocated = descriptor;
211
212 /* Link to running transfer. */
213 UX_TRANSFER_STATE_RESET(transfer_request);
214 hub -> ux_host_class_hub_transfer = transfer_request;
215 status = UX_SUCCESS;
216 #else
217
218 /* Send request to HCD layer. */
219 status = _ux_host_stack_transfer_request(transfer_request);
220
221 /* Did the transfer succeed? */
222 if (status == UX_SUCCESS)
223 {
224
225 /* Is the length valid? */
226 if (transfer_request -> ux_transfer_request_actual_length == UX_HUB_DESCRIPTOR_LENGTH)
227 {
228
229 #if UX_MAX_DEVICES > 1
230 status = _ux_host_class_hub_descriptor_parse(hub, descriptor);
231 if (status != UX_SUCCESS)
232 {
233
234 /* Error trap. */
235 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, status);
236
237 /* If trace is enabled, insert this event into the trace buffer. */
238 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, status, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
239 }
240 #endif
241 }
242 else
243 {
244
245 /* Error trap. */
246 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_DESCRIPTOR_CORRUPTED);
247
248 /* If trace is enabled, insert this event into the trace buffer. */
249 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
250
251 /* The descriptor must be corrupted if we got an invalid length. */
252 status = UX_DESCRIPTOR_CORRUPTED;
253 }
254 }
255
256 /* Free the memory for the descriptor. */
257 _ux_utility_memory_free(descriptor);
258 #endif
259
260 /* Return completion status. */
261 return(status);
262 }
263