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