[USBPORT] Add USB2_CheckTtEndpointInsert().
[reactos.git] / drivers / usb / usbport / usb2.c
1 /*
2 * PROJECT: ReactOS USB Port Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: USBPort USB 2.0 functions
5 * COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6 */
7
8 #include "usbport.h"
9
10 //#define NDEBUG
11 #include <debug.h>
12
13 BOOLEAN
14 NTAPI
15 USB2_AllocateCheck(IN OUT PULONG OutTimeUsed,
16 IN ULONG CalcBusTime,
17 IN ULONG LimitAllocation)
18 {
19 ULONG BusTime;
20 BOOLEAN Result = TRUE;
21
22 BusTime = *OutTimeUsed + CalcBusTime;
23 *OutTimeUsed += CalcBusTime;
24
25 if (BusTime > LimitAllocation)
26 {
27 DPRINT("USB2_AllocateCheck: BusTime > LimitAllocation\n");
28 Result = FALSE;
29 }
30
31 return Result;
32 }
33
34 USHORT
35 NTAPI
36 USB2_AddDataBitStuff(IN USHORT DataTime)
37 {
38 return (DataTime + (DataTime / 16));
39 }
40
41 BOOLEAN
42 NTAPI
43 USB2_CheckTtEndpointInsert(IN PUSB2_TT_ENDPOINT nextTtEndpoint,
44 IN PUSB2_TT_ENDPOINT TtEndpoint)
45 {
46 ULONG TransferType;
47
48 DPRINT("USB2_CheckTtEndpointInsert: nextTtEndpoint - %p, TtEndpoint - %p\n",
49 nextTtEndpoint,
50 TtEndpoint);
51
52 ASSERT(TtEndpoint);
53
54 if (TtEndpoint->CalcBusTime >= (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
55 {
56 DPRINT1("USB2_CheckTtEndpointInsert: Result - FALSE\n");
57 return FALSE;
58 }
59
60 if (!nextTtEndpoint)
61 {
62 DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
63 return TRUE;
64 }
65
66 TransferType = TtEndpoint->TtEndpointParams.TransferType;
67
68 if (nextTtEndpoint->ActualPeriod < TtEndpoint->ActualPeriod &&
69 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
70 {
71 DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
72 return TRUE;
73 }
74
75 if ((nextTtEndpoint->ActualPeriod <= TtEndpoint->ActualPeriod &&
76 TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) ||
77 nextTtEndpoint == TtEndpoint)
78 {
79 DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
80 return TRUE;
81 }
82
83 DPRINT("USB2_CheckTtEndpointInsert: Result - FALSE\n");
84 return FALSE;
85 }
86
87 ULONG
88 NTAPI
89 USB2_GetOverhead(IN PUSB2_TT_ENDPOINT TtEndpoint)
90 {
91 ULONG TransferType;
92 ULONG Direction;
93 ULONG DeviceSpeed;
94 ULONG Overhead;
95 ULONG HostDelay;
96
97 TransferType = TtEndpoint->TtEndpointParams.TransferType;
98 Direction = TtEndpoint->TtEndpointParams.Direction;
99 DeviceSpeed = TtEndpoint->TtEndpointParams.Direction;
100
101 HostDelay = TtEndpoint->Tt->HcExtension->HcDelayTime;
102
103 if (DeviceSpeed == UsbHighSpeed)
104 {
105 if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
106 {
107 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
108 Overhead = HostDelay + USB2_HS_ISOCHRONOUS_OUT_OVERHEAD;
109 else
110 Overhead = HostDelay + USB2_HS_INTERRUPT_OUT_OVERHEAD;
111 }
112 else
113 {
114 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
115 Overhead = HostDelay + USB2_HS_ISOCHRONOUS_IN_OVERHEAD;
116 else
117 Overhead = HostDelay + USB2_HS_ISOCHRONOUS_OUT_OVERHEAD;
118 }
119 }
120 else if (DeviceSpeed == UsbFullSpeed)
121 {
122 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
123 Overhead = HostDelay + USB2_FS_ISOCHRONOUS_OVERHEAD;
124 else
125 Overhead = HostDelay + USB2_FS_INTERRUPT_OVERHEAD;
126 }
127 else
128 {
129 Overhead = HostDelay + USB2_LS_INTERRUPT_OVERHEAD;
130 }
131
132 return Overhead;
133 }
134
135 VOID
136 NTAPI
137 USB2_InitTtEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
138 IN UCHAR TransferType,
139 IN UCHAR Direction,
140 IN UCHAR DeviceSpeed,
141 IN USHORT Period,
142 IN USHORT MaxPacketSize,
143 IN PUSB2_TT Tt)
144 {
145 RtlZeroMemory(TtEndpoint, sizeof(USB2_TT_ENDPOINT));
146
147 TtEndpoint->TtEndpointParams.TransferType = TransferType;
148 TtEndpoint->TtEndpointParams.Direction = Direction;
149 TtEndpoint->TtEndpointParams.DeviceSpeed = DeviceSpeed;
150
151 TtEndpoint->Period = Period;
152 TtEndpoint->MaxPacketSize = MaxPacketSize;
153 TtEndpoint->Tt = Tt;
154 }
155
156 BOOLEAN
157 NTAPI
158 USB2_AllocateTimeForEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
159 IN PUSB2_REBALANCE Rebalance,
160 IN PULONG RebalanceListEntries)
161 {
162 DPRINT("USB2_AllocateTimeForEndpoint: UNIMPLEMENTED. FIXME\n");
163 ASSERT(FALSE);
164 return FALSE;
165 }
166
167 BOOLEAN
168 NTAPI
169 USB2_PromotePeriods(IN PUSB2_TT_ENDPOINT TtEndpoint,
170 IN PUSB2_REBALANCE Rebalance,
171 IN PULONG RebalanceListEntries)
172 {
173 DPRINT1("USB2_PromotePeriods: UNIMPLEMENTED. FIXME\n");
174 ASSERT(FALSE);
175 return FALSE;
176 }
177
178 VOID
179 NTAPI
180 USBPORT_UpdateAllocatedBwTt(IN PUSB2_TT_EXTENSION TtExtension)
181 {
182 ULONG BusBandwidth;
183 ULONG NewBusBandwidth;
184 ULONG MaxBusBandwidth = 0;
185 ULONG MinBusBandwidth;
186 ULONG ix;
187
188 DPRINT("USBPORT_UpdateAllocatedBwTt: TtExtension - %p\n", TtExtension);
189
190 BusBandwidth = TtExtension->BusBandwidth;
191 MinBusBandwidth = BusBandwidth;
192
193 for (ix = 0; ix < USB2_FRAMES; ix++)
194 {
195 NewBusBandwidth = BusBandwidth - TtExtension->Bandwidth[ix];
196
197 if (NewBusBandwidth > MaxBusBandwidth)
198 MaxBusBandwidth = NewBusBandwidth;
199
200 if (NewBusBandwidth < MinBusBandwidth)
201 MinBusBandwidth = NewBusBandwidth;
202 }
203
204 TtExtension->MaxBandwidth = MaxBusBandwidth;
205
206 if (MinBusBandwidth == BusBandwidth)
207 TtExtension->MinBandwidth = 0;
208 else
209 TtExtension->MinBandwidth = MinBusBandwidth;
210 }
211
212 BOOLEAN
213 NTAPI
214 USBPORT_AllocateBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
215 IN PUSBPORT_ENDPOINT Endpoint)
216 {
217 PUSBPORT_DEVICE_EXTENSION FdoExtension;
218 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
219 PUSB2_TT_EXTENSION TtExtension;
220 ULONG TransferType;
221 PUSB2_REBALANCE Rebalance;
222 LIST_ENTRY RebalanceList;
223 ULONG RebalanceListEntries;
224 PUSB2_TT_ENDPOINT TtEndpoint;
225 PUSB2_TT_ENDPOINT RebalanceTtEndpoint;
226
227 PUSB2_TT Tt;
228 USB_DEVICE_SPEED DeviceSpeed;
229 ULONG Period;
230
231 ULONG ix;
232 BOOLEAN Direction;
233 BOOLEAN Result;
234
235 DPRINT("USBPORT_AllocateBandwidthUSB2: FdoDevice - %p, Endpoint - %p\n",
236 FdoDevice,
237 Endpoint);
238
239 EndpointProperties = &Endpoint->EndpointProperties;
240 EndpointProperties->ScheduleOffset = 0;
241
242 if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
243 {
244 DPRINT("USBPORT_AllocateBandwidthUSB2: ENDPOINT_FLAG_ROOTHUB_EP0\n");
245 return TRUE;
246 }
247
248 FdoExtension = FdoDevice->DeviceExtension;
249
250 TransferType = EndpointProperties->TransferType;
251 DPRINT("USBPORT_AllocateBandwidthUSB2: TransferType - %X\n", TransferType);
252
253 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
254 TransferType == USBPORT_TRANSFER_TYPE_BULK)
255 {
256 return TRUE;
257 }
258
259 if (Endpoint->TtExtension)
260 TtExtension = Endpoint->TtExtension;
261 else
262 TtExtension = NULL;
263
264 InitializeListHead(&RebalanceList);
265
266 Rebalance = ExAllocatePoolWithTag(NonPagedPool,
267 sizeof(USB2_REBALANCE),
268 USB_PORT_TAG);
269
270 DPRINT("USBPORT_AllocateBandwidthUSB2: Rebalance - %p, TtExtension - %p\n",
271 Rebalance,
272 TtExtension);
273
274 if (Rebalance)
275 {
276 RtlZeroMemory(Rebalance, sizeof(USB2_REBALANCE));
277
278 TtEndpoint = Endpoint->TtEndpoint;
279 TtEndpoint->Endpoint = Endpoint;
280
281 Direction = EndpointProperties->Direction == USBPORT_TRANSFER_DIRECTION_OUT;
282 DeviceSpeed = EndpointProperties->DeviceSpeed;
283
284 switch (DeviceSpeed)
285 {
286 case UsbLowSpeed:
287 case UsbFullSpeed:
288 {
289 Tt = &TtExtension->Tt;
290 Period = USB2_FRAMES;
291
292 while (Period && Period > EndpointProperties->Period);
293 {
294 Period >>= 1;
295 }
296
297 DPRINT("USBPORT_AllocateBandwidthUSB2: Period - %X\n", Period);
298 break;
299 }
300
301 case UsbHighSpeed:
302 {
303 Tt = &FdoExtension->Usb2Extension->HcTt;
304 Period = EndpointProperties->Period;
305
306 if (EndpointProperties->Period > USB2_MAX_MICROFRAMES)
307 Period = USB2_MAX_MICROFRAMES;
308
309 break;
310 }
311
312 default:
313 {
314 DPRINT1("USBPORT_AllocateBandwidthUSB2: DeviceSpeed - %X!\n", DeviceSpeed);
315 DbgBreakPoint();
316 Tt = &TtExtension->Tt;
317 break;
318 }
319 }
320
321 USB2_InitTtEndpoint(TtEndpoint,
322 TransferType,
323 Direction,
324 DeviceSpeed,
325 Period,
326 EndpointProperties->MaxPacketSize,
327 Tt);
328
329 RebalanceListEntries = USB2_FRAMES - 2;
330
331 Result = USB2_AllocateTimeForEndpoint(TtEndpoint,
332 Rebalance,
333 &RebalanceListEntries);
334
335 if (Result)
336 {
337 Result = USB2_PromotePeriods(TtEndpoint,
338 Rebalance,
339 &RebalanceListEntries);
340 }
341
342 RebalanceListEntries = 0;
343
344 for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
345 {
346 RebalanceListEntries = ix + 1;
347 }
348 }
349 else
350 {
351 RebalanceListEntries = 0;
352 Result = FALSE;
353 }
354
355 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceListEntries - %X, Result - %X\n",
356 RebalanceListEntries,
357 Result);
358
359 for (ix = 0; ix < RebalanceListEntries; ix++)
360 {
361 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceEndpoint[%X] - %X\n",
362 ix,
363 Rebalance->RebalanceEndpoint[ix]);
364
365 RebalanceTtEndpoint = Rebalance->RebalanceEndpoint[ix];
366
367 InsertTailList(&RebalanceList,
368 &RebalanceTtEndpoint->Endpoint->RebalanceLink);
369 }
370
371 if (Rebalance)
372 ExFreePool(Rebalance);
373
374 if (Result)
375 {
376 DPRINT1("USBPORT_AllocateBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
377 ASSERT(FALSE);
378 }
379
380 //USB2_Rebalance(FdoDevice, &RebalanceList);
381
382 if (!TtExtension)
383 {
384 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
385 return Result;
386 }
387
388 for (ix = 0; ix < USB2_FRAMES; ix++)
389 {
390 FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
391 }
392
393 USBPORT_UpdateAllocatedBwTt(TtExtension);
394
395 for (ix = 0; ix < USB2_FRAMES; ix++)
396 {
397 FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth;
398 }
399
400 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
401
402 return Result;
403 }
404
405 VOID
406 NTAPI
407 USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
408 IN PUSBPORT_ENDPOINT Endpoint)
409 {
410 DPRINT1("USBPORT_FreeBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
411 }
412
413 VOID
414 NTAPI
415 USB2_InitTT(IN PUSB2_HC_EXTENSION HcExtension,
416 IN PUSB2_TT Tt)
417 {
418 ULONG ix;
419 ULONG jx;
420
421 DPRINT("USB2_InitTT: HcExtension - %p, Tt - %p\n", HcExtension, Tt);
422
423 Tt->HcExtension = HcExtension;
424 Tt->DelayTime = 1;
425 Tt->MaxTime = USB2_FS_MAX_PERIODIC_ALLOCATION;
426
427 for (ix = 0; ix < USB2_FRAMES; ix++)
428 {
429 Tt->FrameBudget[ix].TimeUsed = USB2_MAX_MICROFRAMES;
430 Tt->FrameBudget[ix].AltEndpoint = NULL;
431
432 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
433 {
434 Tt->TimeCS[ix][jx] = 0;
435 Tt->NumStartSplits[ix][jx] = 0;
436 }
437
438 Tt->FrameBudget[ix].IsoEndpoint = &Tt->IsoEndpoint[ix];
439
440 USB2_InitTtEndpoint(&Tt->IsoEndpoint[ix],
441 USBPORT_TRANSFER_TYPE_ISOCHRONOUS,
442 USBPORT_TRANSFER_DIRECTION_OUT,
443 UsbFullSpeed,
444 USB2_FRAMES,
445 0,
446 Tt);
447
448 Tt->IsoEndpoint[ix].ActualPeriod = USB2_FRAMES;
449 Tt->IsoEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
450 Tt->IsoEndpoint[ix].StartFrame = ix;
451 Tt->IsoEndpoint[ix].StartMicroframe = 0xFF;
452
453 Tt->FrameBudget[ix].IntEndpoint = &Tt->IntEndpoint[ix];
454
455 USB2_InitTtEndpoint(&Tt->IntEndpoint[ix],
456 USBPORT_TRANSFER_TYPE_INTERRUPT,
457 USBPORT_TRANSFER_DIRECTION_OUT,
458 UsbFullSpeed,
459 USB2_FRAMES,
460 0,
461 Tt);
462
463 Tt->IntEndpoint[ix].ActualPeriod = USB2_FRAMES;
464 Tt->IntEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
465 Tt->IntEndpoint[ix].StartFrame = ix;
466 Tt->IntEndpoint[ix].StartMicroframe = 0xFF;
467 }
468 }
469
470 VOID
471 NTAPI
472 USB2_InitController(IN PUSB2_HC_EXTENSION HcExtension)
473 {
474 ULONG ix;
475 ULONG jx;
476
477 DPRINT("USB2_InitController: HcExtension - %p\n", HcExtension);
478
479 HcExtension->MaxHsBusAllocation = USB2_MAX_MICROFRAME_ALLOCATION;
480
481 for (ix = 0; ix < USB2_FRAMES; ix++)
482 {
483 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
484 {
485 HcExtension->TimeUsed[ix][jx] = 0;
486 }
487 }
488
489 HcExtension->HcDelayTime = USB2_CONTROLLER_DELAY;
490
491 USB2_InitTT(HcExtension, &HcExtension->HcTt);
492 }