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