[USBPORT] Add USB2_GetPrevMicroFrame().
[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_AllocateTimeForEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
256 IN PUSB2_REBALANCE Rebalance,
257 IN PULONG RebalanceListEntries)
258 {
259 DPRINT("USB2_AllocateTimeForEndpoint: UNIMPLEMENTED. FIXME\n");
260 ASSERT(FALSE);
261 return FALSE;
262 }
263
264 BOOLEAN
265 NTAPI
266 USB2_PromotePeriods(IN PUSB2_TT_ENDPOINT TtEndpoint,
267 IN PUSB2_REBALANCE Rebalance,
268 IN PULONG RebalanceListEntries)
269 {
270 DPRINT1("USB2_PromotePeriods: UNIMPLEMENTED. FIXME\n");
271 ASSERT(FALSE);
272 return FALSE;
273 }
274
275 VOID
276 NTAPI
277 USBPORT_UpdateAllocatedBwTt(IN PUSB2_TT_EXTENSION TtExtension)
278 {
279 ULONG BusBandwidth;
280 ULONG NewBusBandwidth;
281 ULONG MaxBusBandwidth = 0;
282 ULONG MinBusBandwidth;
283 ULONG ix;
284
285 DPRINT("USBPORT_UpdateAllocatedBwTt: TtExtension - %p\n", TtExtension);
286
287 BusBandwidth = TtExtension->BusBandwidth;
288 MinBusBandwidth = BusBandwidth;
289
290 for (ix = 0; ix < USB2_FRAMES; ix++)
291 {
292 NewBusBandwidth = BusBandwidth - TtExtension->Bandwidth[ix];
293
294 if (NewBusBandwidth > MaxBusBandwidth)
295 MaxBusBandwidth = NewBusBandwidth;
296
297 if (NewBusBandwidth < MinBusBandwidth)
298 MinBusBandwidth = NewBusBandwidth;
299 }
300
301 TtExtension->MaxBandwidth = MaxBusBandwidth;
302
303 if (MinBusBandwidth == BusBandwidth)
304 TtExtension->MinBandwidth = 0;
305 else
306 TtExtension->MinBandwidth = MinBusBandwidth;
307 }
308
309 BOOLEAN
310 NTAPI
311 USBPORT_AllocateBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
312 IN PUSBPORT_ENDPOINT Endpoint)
313 {
314 PUSBPORT_DEVICE_EXTENSION FdoExtension;
315 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
316 PUSB2_TT_EXTENSION TtExtension;
317 ULONG TransferType;
318 PUSB2_REBALANCE Rebalance;
319 LIST_ENTRY RebalanceList;
320 ULONG RebalanceListEntries;
321 PUSB2_TT_ENDPOINT TtEndpoint;
322 PUSB2_TT_ENDPOINT RebalanceTtEndpoint;
323
324 PUSB2_TT Tt;
325 USB_DEVICE_SPEED DeviceSpeed;
326 ULONG Period;
327
328 ULONG ix;
329 BOOLEAN Direction;
330 BOOLEAN Result;
331
332 DPRINT("USBPORT_AllocateBandwidthUSB2: FdoDevice - %p, Endpoint - %p\n",
333 FdoDevice,
334 Endpoint);
335
336 EndpointProperties = &Endpoint->EndpointProperties;
337 EndpointProperties->ScheduleOffset = 0;
338
339 if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
340 {
341 DPRINT("USBPORT_AllocateBandwidthUSB2: ENDPOINT_FLAG_ROOTHUB_EP0\n");
342 return TRUE;
343 }
344
345 FdoExtension = FdoDevice->DeviceExtension;
346
347 TransferType = EndpointProperties->TransferType;
348 DPRINT("USBPORT_AllocateBandwidthUSB2: TransferType - %X\n", TransferType);
349
350 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
351 TransferType == USBPORT_TRANSFER_TYPE_BULK)
352 {
353 return TRUE;
354 }
355
356 if (Endpoint->TtExtension)
357 TtExtension = Endpoint->TtExtension;
358 else
359 TtExtension = NULL;
360
361 InitializeListHead(&RebalanceList);
362
363 Rebalance = ExAllocatePoolWithTag(NonPagedPool,
364 sizeof(USB2_REBALANCE),
365 USB_PORT_TAG);
366
367 DPRINT("USBPORT_AllocateBandwidthUSB2: Rebalance - %p, TtExtension - %p\n",
368 Rebalance,
369 TtExtension);
370
371 if (Rebalance)
372 {
373 RtlZeroMemory(Rebalance, sizeof(USB2_REBALANCE));
374
375 TtEndpoint = Endpoint->TtEndpoint;
376 TtEndpoint->Endpoint = Endpoint;
377
378 Direction = EndpointProperties->Direction == USBPORT_TRANSFER_DIRECTION_OUT;
379 DeviceSpeed = EndpointProperties->DeviceSpeed;
380
381 switch (DeviceSpeed)
382 {
383 case UsbLowSpeed:
384 case UsbFullSpeed:
385 {
386 Tt = &TtExtension->Tt;
387 Period = USB2_FRAMES;
388
389 while (Period && Period > EndpointProperties->Period);
390 {
391 Period >>= 1;
392 }
393
394 DPRINT("USBPORT_AllocateBandwidthUSB2: Period - %X\n", Period);
395 break;
396 }
397
398 case UsbHighSpeed:
399 {
400 Tt = &FdoExtension->Usb2Extension->HcTt;
401 Period = EndpointProperties->Period;
402
403 if (EndpointProperties->Period > USB2_MAX_MICROFRAMES)
404 Period = USB2_MAX_MICROFRAMES;
405
406 break;
407 }
408
409 default:
410 {
411 DPRINT1("USBPORT_AllocateBandwidthUSB2: DeviceSpeed - %X!\n", DeviceSpeed);
412 DbgBreakPoint();
413 Tt = &TtExtension->Tt;
414 break;
415 }
416 }
417
418 USB2_InitTtEndpoint(TtEndpoint,
419 TransferType,
420 Direction,
421 DeviceSpeed,
422 Period,
423 EndpointProperties->MaxPacketSize,
424 Tt);
425
426 RebalanceListEntries = USB2_FRAMES - 2;
427
428 Result = USB2_AllocateTimeForEndpoint(TtEndpoint,
429 Rebalance,
430 &RebalanceListEntries);
431
432 if (Result)
433 {
434 Result = USB2_PromotePeriods(TtEndpoint,
435 Rebalance,
436 &RebalanceListEntries);
437 }
438
439 RebalanceListEntries = 0;
440
441 for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
442 {
443 RebalanceListEntries = ix + 1;
444 }
445 }
446 else
447 {
448 RebalanceListEntries = 0;
449 Result = FALSE;
450 }
451
452 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceListEntries - %X, Result - %X\n",
453 RebalanceListEntries,
454 Result);
455
456 for (ix = 0; ix < RebalanceListEntries; ix++)
457 {
458 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceEndpoint[%X] - %X\n",
459 ix,
460 Rebalance->RebalanceEndpoint[ix]);
461
462 RebalanceTtEndpoint = Rebalance->RebalanceEndpoint[ix];
463
464 InsertTailList(&RebalanceList,
465 &RebalanceTtEndpoint->Endpoint->RebalanceLink);
466 }
467
468 if (Rebalance)
469 ExFreePool(Rebalance);
470
471 if (Result)
472 {
473 DPRINT1("USBPORT_AllocateBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
474 ASSERT(FALSE);
475 }
476
477 //USB2_Rebalance(FdoDevice, &RebalanceList);
478
479 if (!TtExtension)
480 {
481 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
482 return Result;
483 }
484
485 for (ix = 0; ix < USB2_FRAMES; ix++)
486 {
487 FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
488 }
489
490 USBPORT_UpdateAllocatedBwTt(TtExtension);
491
492 for (ix = 0; ix < USB2_FRAMES; ix++)
493 {
494 FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth;
495 }
496
497 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
498
499 return Result;
500 }
501
502 VOID
503 NTAPI
504 USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
505 IN PUSBPORT_ENDPOINT Endpoint)
506 {
507 DPRINT1("USBPORT_FreeBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
508 }
509
510 VOID
511 NTAPI
512 USB2_InitTT(IN PUSB2_HC_EXTENSION HcExtension,
513 IN PUSB2_TT Tt)
514 {
515 ULONG ix;
516 ULONG jx;
517
518 DPRINT("USB2_InitTT: HcExtension - %p, Tt - %p\n", HcExtension, Tt);
519
520 Tt->HcExtension = HcExtension;
521 Tt->DelayTime = 1;
522 Tt->MaxTime = USB2_FS_MAX_PERIODIC_ALLOCATION;
523
524 for (ix = 0; ix < USB2_FRAMES; ix++)
525 {
526 Tt->FrameBudget[ix].TimeUsed = USB2_MAX_MICROFRAMES;
527 Tt->FrameBudget[ix].AltEndpoint = NULL;
528
529 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
530 {
531 Tt->TimeCS[ix][jx] = 0;
532 Tt->NumStartSplits[ix][jx] = 0;
533 }
534
535 Tt->FrameBudget[ix].IsoEndpoint = &Tt->IsoEndpoint[ix];
536
537 USB2_InitTtEndpoint(&Tt->IsoEndpoint[ix],
538 USBPORT_TRANSFER_TYPE_ISOCHRONOUS,
539 USBPORT_TRANSFER_DIRECTION_OUT,
540 UsbFullSpeed,
541 USB2_FRAMES,
542 0,
543 Tt);
544
545 Tt->IsoEndpoint[ix].ActualPeriod = USB2_FRAMES;
546 Tt->IsoEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
547 Tt->IsoEndpoint[ix].StartFrame = ix;
548 Tt->IsoEndpoint[ix].StartMicroframe = 0xFF;
549
550 Tt->FrameBudget[ix].IntEndpoint = &Tt->IntEndpoint[ix];
551
552 USB2_InitTtEndpoint(&Tt->IntEndpoint[ix],
553 USBPORT_TRANSFER_TYPE_INTERRUPT,
554 USBPORT_TRANSFER_DIRECTION_OUT,
555 UsbFullSpeed,
556 USB2_FRAMES,
557 0,
558 Tt);
559
560 Tt->IntEndpoint[ix].ActualPeriod = USB2_FRAMES;
561 Tt->IntEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
562 Tt->IntEndpoint[ix].StartFrame = ix;
563 Tt->IntEndpoint[ix].StartMicroframe = 0xFF;
564 }
565 }
566
567 VOID
568 NTAPI
569 USB2_InitController(IN PUSB2_HC_EXTENSION HcExtension)
570 {
571 ULONG ix;
572 ULONG jx;
573
574 DPRINT("USB2_InitController: HcExtension - %p\n", HcExtension);
575
576 HcExtension->MaxHsBusAllocation = USB2_MAX_MICROFRAME_ALLOCATION;
577
578 for (ix = 0; ix < USB2_FRAMES; ix++)
579 {
580 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
581 {
582 HcExtension->TimeUsed[ix][jx] = 0;
583 }
584 }
585
586 HcExtension->HcDelayTime = USB2_CONTROLLER_DELAY;
587
588 USB2_InitTT(HcExtension, &HcExtension->HcTt);
589 }