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 /**   Host Stack                                                          */
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_stack.h"
30 
31 
32 #if UX_MAX_DEVICES > 1
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_stack_bandwidth_check                      PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function will check if there is enough bandwidth on the USB    */
46 /*    for the specified endpoint. The bandwidth requirement is calculated */
47 /*    by the MaxPacketSize field of endpoint and the speed of the         */
48 /*    endpoint. If the device is on a 1.1 bus or it is a 1.1 device       */
49 /*    behind a 2.0 hub on a 2.0 bus, the device bandwidth must be         */
50 /*    multiplied by 8 on the 1.1 segment.                                 */
51 /*                                                                        */
52 /*    This algorithm takes into account both TT bandwidth and HCD         */
53 /*    bandwidth. The TTs are attached to the device structure and not     */
54 /*    the hub structure in order to make the stack agnostic of the hub    */
55 /*    class.                                                              */
56 /*                                                                        */
57 /*  INPUT                                                                 */
58 /*                                                                        */
59 /*    HCD                                   Pointer to HCD                */
60 /*    endpoint                              Pointer to endpoint           */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    Completion Status                                                   */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    None                                                                */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    USBX Components                                                     */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
79 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            optimized based on compile  */
81 /*                                            definitions,                */
82 /*                                            resulting in version 6.1    */
83 /*                                                                        */
84 /**************************************************************************/
_ux_host_stack_bandwidth_check(UX_HCD * hcd,UX_ENDPOINT * endpoint)85 UINT  _ux_host_stack_bandwidth_check(UX_HCD *hcd, UX_ENDPOINT *endpoint)
86 {
87 
88 UX_DEVICE       *device;
89 UX_DEVICE       *parent_device;
90 USHORT          hcd_bandwidth_claimed;
91 USHORT          max_packet_size;
92 LONG            packet_size;
93 USHORT          tt_bandwidth_claimed =  0;
94 ULONG           port_index;
95 ULONG           port_map;
96 ULONG           tt_index;
97 const UCHAR     overheads[4][3] = {
98 /*   LS  FS   HS   */
99     {63, 45, 173}, /* Control */
100     { 0,  9,  38}, /* Isochronous */
101     { 0, 13,  55}, /* Bulk */
102     {19, 13,  55}  /* Interrupt */
103 };
104 
105     /* Get the pointer to the device.  */
106     device =  endpoint -> ux_endpoint_device;
107 
108     /* Calculate the bandwidth. From USB spec.
109      *
110      * The frame unit consumed per byte is like follow:
111      *              Bytes/FrameUnit     FrameUnit/byte  FrameUnit/byte
112      *              (Overhead included) (HS baseline)   (FS baseline)
113      * Low Speed       187.5                40             8
114      * Full Speed     1500                   5             1
115      * High Speed     7500                   1            1/5
116      *
117      * The overhead is like follow:
118      *               Control Isochronous Bulk Interrupt
119      * bmAttribute     (0)       (1)     (2)     (3)
120      * Low Speed        63       --      --      19
121      * Full Speed       45        9      13      13
122      * High Speed      173       38      55      55
123      *
124      * Worst case bit stuffing is calculated as 1.1667 (7/6) times the raw time.
125      */
126 
127     /* Get maximum packet size.  */
128     max_packet_size  = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK;
129 
130     /* Rough time for possible Bit Stuffing.  */
131     packet_size = (max_packet_size * 7 + 5) / 6;
132 
133     /* Add overhead.  */
134     packet_size += overheads[endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE][device -> ux_device_speed];
135     max_packet_size = (USHORT)packet_size;
136 
137     /* Check for high-speed endpoint.  */
138     if (device -> ux_device_speed == UX_HIGH_SPEED_DEVICE)
139     {
140 
141         /* Get number of transactions.  */
142         max_packet_size = (USHORT)(max_packet_size *
143                     (((endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK) >>
144                         UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT) + 1));
145     }
146 
147     /* Calculate the bandwidth claimed by this endpoint for the main bus.  */
148     if (hcd -> ux_hcd_version != 0x200)
149     {
150 
151         if (device -> ux_device_speed == UX_LOW_SPEED_DEVICE)
152             /* Low speed transfer takes 40x more units than high speed. */
153             hcd_bandwidth_claimed =  (USHORT)(max_packet_size * 8 * 5);
154         else
155         {
156 
157             if (device -> ux_device_speed == UX_FULL_SPEED_DEVICE)
158                 /* Full speed transfer takes 5x more units than high speed. */
159                 hcd_bandwidth_claimed =  (USHORT)(max_packet_size * 5);
160             else
161                 /* Use high speed timing as base for bus bandwidth calculation. */
162                 hcd_bandwidth_claimed =  (USHORT)max_packet_size;
163         }
164     }
165     else
166     {
167 
168         hcd_bandwidth_claimed =  (USHORT)max_packet_size;
169         if (device -> ux_device_speed == UX_LOW_SPEED_DEVICE)
170             /* Low speed transfer takes 8x more units than full speed. */
171             tt_bandwidth_claimed =  (USHORT)(max_packet_size * 8);
172         else
173             /* Use full speed timing as base for TT bandwidth calculation. */
174             tt_bandwidth_claimed =  (USHORT)max_packet_size;
175     }
176 
177     /* Do we have enough on the bus for this new endpoint?  */
178     if (hcd -> ux_hcd_available_bandwidth < hcd_bandwidth_claimed)
179     {
180 
181         /* If trace is enabled, insert this event into the trace buffer.  */
182         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_BANDWIDTH_AVAILABLE, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
183 
184         /* Error trap. */
185         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_NO_BANDWIDTH_AVAILABLE);
186 
187         return(UX_NO_BANDWIDTH_AVAILABLE);
188     }
189 
190     /* We need to take care of the case where the endpoint belongs to a USB 1.1
191        device that sits behind a 2.0 hub. We ignore cases where the device
192        is either high speed or the bus is 1.1.  */
193     if ((device -> ux_device_speed == UX_HIGH_SPEED_DEVICE) || (hcd -> ux_hcd_version != 0x200))
194     {
195 
196         /* The device is high speed, therefore no need for TT.  */
197         return(UX_SUCCESS);
198     }
199 
200     /* We have a 1.1 device, check if the parent is a 2.0 hub.  */
201     parent_device =  device -> ux_device_parent;
202     if (parent_device == UX_NULL)
203     {
204 
205         /* We are at the root, this controller must support 1.1 then! */
206         return(UX_SUCCESS);
207     }
208 
209     /* We get here when the parent is a hub. The problem occurs when the hub is itself
210        connected to a chain of hubs. We need to find the first 2.0 hub parent to this
211        chain to check the TT. We need to remember the port on which the first 1.1
212        device is hooked to.  */
213     port_index =  device -> ux_device_port_location - 1;
214 
215     /* Scan the chain of hubs upward.  */
216     while (parent_device != UX_NULL)
217     {
218 
219         /* Determine if the device is high speed.  */
220         if (parent_device -> ux_device_speed == UX_HIGH_SPEED_DEVICE)
221         {
222 
223             /* The device is a high speed hub, find the TT that manages the port.
224                The first 1.1 device is connected to. First we calculate the port
225                mapping bit.  */
226             port_map = (ULONG)(1 << port_index);
227 
228             /* Parse all the TTs attached to the hub.  */
229             for (tt_index = 0; tt_index < UX_MAX_TT; tt_index++)
230             {
231 
232                 /* Check if this TT owns the port where the device is attached.  */
233                 if ((parent_device -> ux_device_hub_tt[tt_index].ux_hub_tt_port_mapping & port_map) != 0)
234                 {
235 
236                     /* We have found the port, check if the tt can give us the bandwidth
237                        we want to claim.  */
238                     if (parent_device -> ux_device_hub_tt[tt_index].ux_hub_tt_max_bandwidth < tt_bandwidth_claimed)
239                     {
240 
241                         /* If trace is enabled, insert this event into the trace buffer.  */
242                         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_BANDWIDTH_AVAILABLE, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
243 
244                         /* Error trap. */
245                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_NO_BANDWIDTH_AVAILABLE);
246 
247                         return(UX_NO_BANDWIDTH_AVAILABLE);
248                     }
249 
250                     else
251                         return(UX_SUCCESS);
252                 }
253             }
254 
255             /* If trace is enabled, insert this event into the trace buffer.  */
256             UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_BANDWIDTH_AVAILABLE, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
257 
258             /* Error trap. */
259             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_NO_BANDWIDTH_AVAILABLE);
260 
261             /* We should never get here !!!!! */
262             return(UX_NO_BANDWIDTH_AVAILABLE);
263         }
264 
265         /* We now remember where this hub is located on the parent.  */
266         port_index =  parent_device -> ux_device_port_location - 1;
267 
268         /* We go up one level in the hub chain.  */
269         parent_device =  parent_device -> ux_device_parent;
270     }
271 
272     /* We get here when we have not found a 2.0 hub in the list and we got to the root port.  */
273     return(UX_SUCCESS);
274 }
275 #endif /* #if UX_MAX_DEVICES > 1 */
276