5e0ace37c692105124681fe25615e41884a9ab0d
[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 VOID
42 NTAPI
43 USB2_IncMicroFrame(OUT PUCHAR frame,
44 OUT PUCHAR uframe)
45 {
46 ++*uframe;
47
48 if (*uframe > (USB2_MICROFRAMES - 1))
49 {
50 *uframe = 0;
51 *frame = (*frame + 1) & (USB2_FRAMES - 1);
52 }
53 }
54
55 VOID
56 NTAPI
57 USB2_GetPrevMicroFrame(OUT PUCHAR frame,
58 OUT PUCHAR uframe)
59 {
60 *uframe = USB2_MICROFRAMES - 1;
61
62 if (*frame)
63 --*frame;
64 else
65 *frame = USB2_FRAMES - 1;
66 }
67
68 BOOLEAN
69 NTAPI
70 USB2_CheckTtEndpointInsert(IN PUSB2_TT_ENDPOINT nextTtEndpoint,
71 IN PUSB2_TT_ENDPOINT TtEndpoint)
72 {
73 ULONG TransferType;
74
75 DPRINT("USB2_CheckTtEndpointInsert: nextTtEndpoint - %p, TtEndpoint - %p\n",
76 nextTtEndpoint,
77 TtEndpoint);
78
79 ASSERT(TtEndpoint);
80
81 if (TtEndpoint->CalcBusTime >= (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
82 {
83 DPRINT1("USB2_CheckTtEndpointInsert: Result - FALSE\n");
84 return FALSE;
85 }
86
87 if (!nextTtEndpoint)
88 {
89 DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
90 return TRUE;
91 }
92
93 TransferType = TtEndpoint->TtEndpointParams.TransferType;
94
95 if (nextTtEndpoint->ActualPeriod < TtEndpoint->ActualPeriod &&
96 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
97 {
98 DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
99 return TRUE;
100 }
101
102 if ((nextTtEndpoint->ActualPeriod <= TtEndpoint->ActualPeriod &&
103 TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) ||
104 nextTtEndpoint == TtEndpoint)
105 {
106 DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
107 return TRUE;
108 }
109
110 DPRINT("USB2_CheckTtEndpointInsert: Result - FALSE\n");
111 return FALSE;
112 }
113
114 ULONG
115 NTAPI
116 USB2_GetOverhead(IN PUSB2_TT_ENDPOINT TtEndpoint)
117 {
118 ULONG TransferType;
119 ULONG Direction;
120 ULONG DeviceSpeed;
121 ULONG Overhead;
122 ULONG HostDelay;
123
124 TransferType = TtEndpoint->TtEndpointParams.TransferType;
125 Direction = TtEndpoint->TtEndpointParams.Direction;
126 DeviceSpeed = TtEndpoint->TtEndpointParams.Direction;
127
128 HostDelay = TtEndpoint->Tt->HcExtension->HcDelayTime;
129
130 if (DeviceSpeed == UsbHighSpeed)
131 {
132 if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
133 {
134 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
135 Overhead = HostDelay + USB2_HS_ISOCHRONOUS_OUT_OVERHEAD;
136 else
137 Overhead = HostDelay + USB2_HS_INTERRUPT_OUT_OVERHEAD;
138 }
139 else
140 {
141 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
142 Overhead = HostDelay + USB2_HS_ISOCHRONOUS_IN_OVERHEAD;
143 else
144 Overhead = HostDelay + USB2_HS_ISOCHRONOUS_OUT_OVERHEAD;
145 }
146 }
147 else if (DeviceSpeed == UsbFullSpeed)
148 {
149 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
150 Overhead = HostDelay + USB2_FS_ISOCHRONOUS_OVERHEAD;
151 else
152 Overhead = HostDelay + USB2_FS_INTERRUPT_OVERHEAD;
153 }
154 else
155 {
156 Overhead = HostDelay + USB2_LS_INTERRUPT_OVERHEAD;
157 }
158
159 return Overhead;
160 }
161
162 ULONG
163 NTAPI
164 USB2_GetLastIsoTime(IN PUSB2_TT_ENDPOINT TtEndpoint,
165 IN ULONG Frame)
166 {
167 PUSB2_TT_ENDPOINT nextTtEndpoint;
168 ULONG Result;
169
170 DPRINT("USB2_GetLastIsoTime: TtEndpoint - %p, Frame - %X\n",
171 TtEndpoint,
172 Frame);
173
174 nextTtEndpoint = TtEndpoint->Tt->FrameBudget[Frame].IsoEndpoint->NextTtEndpoint;
175
176 if (nextTtEndpoint ||
177 (nextTtEndpoint = TtEndpoint->Tt->FrameBudget[Frame].AltEndpoint) != NULL)
178 {
179 Result = nextTtEndpoint->StartTime + nextTtEndpoint->CalcBusTime;
180 }
181 else
182 {
183 Result = USB2_FS_SOF_TIME;
184 }
185
186 return Result;
187 }
188
189 ULONG
190 NTAPI
191 USB2_GetStartTime(IN PUSB2_TT_ENDPOINT nextTtEndpoint,
192 IN PUSB2_TT_ENDPOINT TtEndpoint,
193 IN PUSB2_TT_ENDPOINT prevTtEndpoint,
194 IN ULONG Frame)
195 {
196 PUSB2_TT_ENDPOINT ttEndpoint;
197 ULONG TransferType;
198
199 DPRINT("USB2_GetStartTime: nextTtEndpoint - %p, TtEndpoint - %p, prevTtEndpoint - %p, Frame - %X\n",
200 nextTtEndpoint,
201 TtEndpoint,
202 prevTtEndpoint,
203 Frame);
204
205 TransferType = TtEndpoint->TtEndpointParams.TransferType;
206
207 if (nextTtEndpoint && TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
208 {
209 return nextTtEndpoint->StartTime + nextTtEndpoint->CalcBusTime;
210 }
211
212 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
213 {
214 ttEndpoint = TtEndpoint->Tt->FrameBudget[Frame].AltEndpoint;
215
216 if (ttEndpoint)
217 return ttEndpoint->StartTime + ttEndpoint->CalcBusTime;
218 else
219 return USB2_FS_SOF_TIME;
220 }
221 else
222 {
223 ttEndpoint = prevTtEndpoint;
224
225 if (ttEndpoint == TtEndpoint->Tt->FrameBudget[Frame].IntEndpoint)
226 return USB2_GetLastIsoTime(TtEndpoint, Frame);
227 else
228 return ttEndpoint->StartTime + ttEndpoint->CalcBusTime;
229 }
230 }
231
232 VOID
233 NTAPI
234 USB2_InitTtEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
235 IN UCHAR TransferType,
236 IN UCHAR Direction,
237 IN UCHAR DeviceSpeed,
238 IN USHORT Period,
239 IN USHORT MaxPacketSize,
240 IN PUSB2_TT Tt)
241 {
242 RtlZeroMemory(TtEndpoint, sizeof(USB2_TT_ENDPOINT));
243
244 TtEndpoint->TtEndpointParams.TransferType = TransferType;
245 TtEndpoint->TtEndpointParams.Direction = Direction;
246 TtEndpoint->TtEndpointParams.DeviceSpeed = DeviceSpeed;
247
248 TtEndpoint->Period = Period;
249 TtEndpoint->MaxPacketSize = MaxPacketSize;
250 TtEndpoint->Tt = Tt;
251 }
252
253 BOOLEAN
254 NTAPI
255 USB2_AllocateHS(IN PUSB2_TT_ENDPOINT TtEndpoint,
256 IN ULONG Frame)
257 {
258 DPRINT("USB2_AllocateHS: UNIMPLEMENTED FIXME\n");
259 return FALSE;
260 }
261
262 BOOLEAN
263 NTAPI
264 USB2_DeallocateEndpointBudget(IN PUSB2_TT_ENDPOINT TtEndpoint,
265 IN PUSB2_REBALANCE Rebalance,
266 IN PULONG RebalanceListEntries,
267 IN ULONG MaxFrames)
268 {
269 DPRINT("USB2_DeallocateEndpointBudget: UNIMPLEMENTED FIXME\n");
270 ASSERT(FALSE);
271 return FALSE;
272 }
273
274 BOOLEAN
275 NTAPI
276 USB2_AllocateTimeForEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
277 IN PUSB2_REBALANCE Rebalance,
278 IN PULONG RebalanceListEntries)
279 {
280 DPRINT("USB2_AllocateTimeForEndpoint: UNIMPLEMENTED. FIXME\n");
281 ASSERT(FALSE);
282 return FALSE;
283 }
284
285 BOOLEAN
286 NTAPI
287 USB2_PromotePeriods(IN PUSB2_TT_ENDPOINT TtEndpoint,
288 IN PUSB2_REBALANCE Rebalance,
289 IN PULONG RebalanceListEntries)
290 {
291 DPRINT1("USB2_PromotePeriods: UNIMPLEMENTED. FIXME\n");
292 ASSERT(FALSE);
293 return FALSE;
294 }
295
296 VOID
297 NTAPI
298 USBPORT_UpdateAllocatedBwTt(IN PUSB2_TT_EXTENSION TtExtension)
299 {
300 ULONG BusBandwidth;
301 ULONG NewBusBandwidth;
302 ULONG MaxBusBandwidth = 0;
303 ULONG MinBusBandwidth;
304 ULONG ix;
305
306 DPRINT("USBPORT_UpdateAllocatedBwTt: TtExtension - %p\n", TtExtension);
307
308 BusBandwidth = TtExtension->BusBandwidth;
309 MinBusBandwidth = BusBandwidth;
310
311 for (ix = 0; ix < USB2_FRAMES; ix++)
312 {
313 NewBusBandwidth = BusBandwidth - TtExtension->Bandwidth[ix];
314
315 if (NewBusBandwidth > MaxBusBandwidth)
316 MaxBusBandwidth = NewBusBandwidth;
317
318 if (NewBusBandwidth < MinBusBandwidth)
319 MinBusBandwidth = NewBusBandwidth;
320 }
321
322 TtExtension->MaxBandwidth = MaxBusBandwidth;
323
324 if (MinBusBandwidth == BusBandwidth)
325 TtExtension->MinBandwidth = 0;
326 else
327 TtExtension->MinBandwidth = MinBusBandwidth;
328 }
329
330 BOOLEAN
331 NTAPI
332 USBPORT_AllocateBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
333 IN PUSBPORT_ENDPOINT Endpoint)
334 {
335 PUSBPORT_DEVICE_EXTENSION FdoExtension;
336 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
337 PUSB2_TT_EXTENSION TtExtension;
338 ULONG TransferType;
339 PUSB2_REBALANCE Rebalance;
340 LIST_ENTRY RebalanceList;
341 ULONG RebalanceListEntries;
342 PUSB2_TT_ENDPOINT TtEndpoint;
343 PUSB2_TT_ENDPOINT RebalanceTtEndpoint;
344
345 PUSB2_TT Tt;
346 USB_DEVICE_SPEED DeviceSpeed;
347 ULONG Period;
348
349 ULONG ix;
350 BOOLEAN Direction;
351 BOOLEAN Result;
352
353 DPRINT("USBPORT_AllocateBandwidthUSB2: FdoDevice - %p, Endpoint - %p\n",
354 FdoDevice,
355 Endpoint);
356
357 EndpointProperties = &Endpoint->EndpointProperties;
358 EndpointProperties->ScheduleOffset = 0;
359
360 if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
361 {
362 DPRINT("USBPORT_AllocateBandwidthUSB2: ENDPOINT_FLAG_ROOTHUB_EP0\n");
363 return TRUE;
364 }
365
366 FdoExtension = FdoDevice->DeviceExtension;
367
368 TransferType = EndpointProperties->TransferType;
369 DPRINT("USBPORT_AllocateBandwidthUSB2: TransferType - %X\n", TransferType);
370
371 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
372 TransferType == USBPORT_TRANSFER_TYPE_BULK)
373 {
374 return TRUE;
375 }
376
377 if (Endpoint->TtExtension)
378 TtExtension = Endpoint->TtExtension;
379 else
380 TtExtension = NULL;
381
382 InitializeListHead(&RebalanceList);
383
384 Rebalance = ExAllocatePoolWithTag(NonPagedPool,
385 sizeof(USB2_REBALANCE),
386 USB_PORT_TAG);
387
388 DPRINT("USBPORT_AllocateBandwidthUSB2: Rebalance - %p, TtExtension - %p\n",
389 Rebalance,
390 TtExtension);
391
392 if (Rebalance)
393 {
394 RtlZeroMemory(Rebalance, sizeof(USB2_REBALANCE));
395
396 TtEndpoint = Endpoint->TtEndpoint;
397 TtEndpoint->Endpoint = Endpoint;
398
399 Direction = EndpointProperties->Direction == USBPORT_TRANSFER_DIRECTION_OUT;
400 DeviceSpeed = EndpointProperties->DeviceSpeed;
401
402 switch (DeviceSpeed)
403 {
404 case UsbLowSpeed:
405 case UsbFullSpeed:
406 {
407 Tt = &TtExtension->Tt;
408 Period = USB2_FRAMES;
409
410 while (Period && Period > EndpointProperties->Period);
411 {
412 Period >>= 1;
413 }
414
415 DPRINT("USBPORT_AllocateBandwidthUSB2: Period - %X\n", Period);
416 break;
417 }
418
419 case UsbHighSpeed:
420 {
421 Tt = &FdoExtension->Usb2Extension->HcTt;
422 Period = EndpointProperties->Period;
423
424 if (EndpointProperties->Period > USB2_MAX_MICROFRAMES)
425 Period = USB2_MAX_MICROFRAMES;
426
427 break;
428 }
429
430 default:
431 {
432 DPRINT1("USBPORT_AllocateBandwidthUSB2: DeviceSpeed - %X!\n", DeviceSpeed);
433 DbgBreakPoint();
434 Tt = &TtExtension->Tt;
435 break;
436 }
437 }
438
439 USB2_InitTtEndpoint(TtEndpoint,
440 TransferType,
441 Direction,
442 DeviceSpeed,
443 Period,
444 EndpointProperties->MaxPacketSize,
445 Tt);
446
447 RebalanceListEntries = USB2_FRAMES - 2;
448
449 Result = USB2_AllocateTimeForEndpoint(TtEndpoint,
450 Rebalance,
451 &RebalanceListEntries);
452
453 if (Result)
454 {
455 Result = USB2_PromotePeriods(TtEndpoint,
456 Rebalance,
457 &RebalanceListEntries);
458 }
459
460 RebalanceListEntries = 0;
461
462 for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
463 {
464 RebalanceListEntries = ix + 1;
465 }
466 }
467 else
468 {
469 RebalanceListEntries = 0;
470 Result = FALSE;
471 }
472
473 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceListEntries - %X, Result - %X\n",
474 RebalanceListEntries,
475 Result);
476
477 for (ix = 0; ix < RebalanceListEntries; ix++)
478 {
479 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceEndpoint[%X] - %X\n",
480 ix,
481 Rebalance->RebalanceEndpoint[ix]);
482
483 RebalanceTtEndpoint = Rebalance->RebalanceEndpoint[ix];
484
485 InsertTailList(&RebalanceList,
486 &RebalanceTtEndpoint->Endpoint->RebalanceLink);
487 }
488
489 if (Rebalance)
490 ExFreePool(Rebalance);
491
492 if (Result)
493 {
494 DPRINT1("USBPORT_AllocateBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
495 ASSERT(FALSE);
496 }
497
498 //USB2_Rebalance(FdoDevice, &RebalanceList);
499
500 if (!TtExtension)
501 {
502 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
503 return Result;
504 }
505
506 for (ix = 0; ix < USB2_FRAMES; ix++)
507 {
508 FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
509 }
510
511 USBPORT_UpdateAllocatedBwTt(TtExtension);
512
513 for (ix = 0; ix < USB2_FRAMES; ix++)
514 {
515 FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth;
516 }
517
518 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
519
520 return Result;
521 }
522
523 VOID
524 NTAPI
525 USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
526 IN PUSBPORT_ENDPOINT Endpoint)
527 {
528 DPRINT1("USBPORT_FreeBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
529 }
530
531 VOID
532 NTAPI
533 USB2_InitTT(IN PUSB2_HC_EXTENSION HcExtension,
534 IN PUSB2_TT Tt)
535 {
536 ULONG ix;
537 ULONG jx;
538
539 DPRINT("USB2_InitTT: HcExtension - %p, Tt - %p\n", HcExtension, Tt);
540
541 Tt->HcExtension = HcExtension;
542 Tt->DelayTime = 1;
543 Tt->MaxTime = USB2_FS_MAX_PERIODIC_ALLOCATION;
544
545 for (ix = 0; ix < USB2_FRAMES; ix++)
546 {
547 Tt->FrameBudget[ix].TimeUsed = USB2_MAX_MICROFRAMES;
548 Tt->FrameBudget[ix].AltEndpoint = NULL;
549
550 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
551 {
552 Tt->TimeCS[ix][jx] = 0;
553 Tt->NumStartSplits[ix][jx] = 0;
554 }
555
556 Tt->FrameBudget[ix].IsoEndpoint = &Tt->IsoEndpoint[ix];
557
558 USB2_InitTtEndpoint(&Tt->IsoEndpoint[ix],
559 USBPORT_TRANSFER_TYPE_ISOCHRONOUS,
560 USBPORT_TRANSFER_DIRECTION_OUT,
561 UsbFullSpeed,
562 USB2_FRAMES,
563 0,
564 Tt);
565
566 Tt->IsoEndpoint[ix].ActualPeriod = USB2_FRAMES;
567 Tt->IsoEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
568 Tt->IsoEndpoint[ix].StartFrame = ix;
569 Tt->IsoEndpoint[ix].StartMicroframe = 0xFF;
570
571 Tt->FrameBudget[ix].IntEndpoint = &Tt->IntEndpoint[ix];
572
573 USB2_InitTtEndpoint(&Tt->IntEndpoint[ix],
574 USBPORT_TRANSFER_TYPE_INTERRUPT,
575 USBPORT_TRANSFER_DIRECTION_OUT,
576 UsbFullSpeed,
577 USB2_FRAMES,
578 0,
579 Tt);
580
581 Tt->IntEndpoint[ix].ActualPeriod = USB2_FRAMES;
582 Tt->IntEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
583 Tt->IntEndpoint[ix].StartFrame = ix;
584 Tt->IntEndpoint[ix].StartMicroframe = 0xFF;
585 }
586 }
587
588 VOID
589 NTAPI
590 USB2_InitController(IN PUSB2_HC_EXTENSION HcExtension)
591 {
592 ULONG ix;
593 ULONG jx;
594
595 DPRINT("USB2_InitController: HcExtension - %p\n", HcExtension);
596
597 HcExtension->MaxHsBusAllocation = USB2_MAX_MICROFRAME_ALLOCATION;
598
599 for (ix = 0; ix < USB2_FRAMES; ix++)
600 {
601 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
602 {
603 HcExtension->TimeUsed[ix][jx] = 0;
604 }
605 }
606
607 HcExtension->HcDelayTime = USB2_CONTROLLER_DELAY;
608
609 USB2_InitTT(HcExtension, &HcExtension->HcTt);
610 }