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