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