94c2844bd73c459c0cfafb6e32b93f2c9167e523
[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 ULONG
136 NTAPI
137 USB2_GetLastIsoTime(IN PUSB2_TT_ENDPOINT TtEndpoint,
138 IN ULONG Frame)
139 {
140 PUSB2_TT_ENDPOINT nextTtEndpoint;
141 ULONG Result;
142
143 DPRINT("USB2_GetLastIsoTime: TtEndpoint - %p, Frame - %X\n",
144 TtEndpoint,
145 Frame);
146
147 nextTtEndpoint = TtEndpoint->Tt->FrameBudget[Frame].IsoEndpoint->NextTtEndpoint;
148
149 if (nextTtEndpoint ||
150 (nextTtEndpoint = TtEndpoint->Tt->FrameBudget[Frame].AltEndpoint) != NULL)
151 {
152 Result = nextTtEndpoint->StartTime + nextTtEndpoint->CalcBusTime;
153 }
154 else
155 {
156 Result = USB2_FS_SOF_TIME;
157 }
158
159 return Result;
160 }
161
162 VOID
163 NTAPI
164 USB2_InitTtEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
165 IN UCHAR TransferType,
166 IN UCHAR Direction,
167 IN UCHAR DeviceSpeed,
168 IN USHORT Period,
169 IN USHORT MaxPacketSize,
170 IN PUSB2_TT Tt)
171 {
172 RtlZeroMemory(TtEndpoint, sizeof(USB2_TT_ENDPOINT));
173
174 TtEndpoint->TtEndpointParams.TransferType = TransferType;
175 TtEndpoint->TtEndpointParams.Direction = Direction;
176 TtEndpoint->TtEndpointParams.DeviceSpeed = DeviceSpeed;
177
178 TtEndpoint->Period = Period;
179 TtEndpoint->MaxPacketSize = MaxPacketSize;
180 TtEndpoint->Tt = Tt;
181 }
182
183 BOOLEAN
184 NTAPI
185 USB2_AllocateTimeForEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
186 IN PUSB2_REBALANCE Rebalance,
187 IN PULONG RebalanceListEntries)
188 {
189 DPRINT("USB2_AllocateTimeForEndpoint: UNIMPLEMENTED. FIXME\n");
190 ASSERT(FALSE);
191 return FALSE;
192 }
193
194 BOOLEAN
195 NTAPI
196 USB2_PromotePeriods(IN PUSB2_TT_ENDPOINT TtEndpoint,
197 IN PUSB2_REBALANCE Rebalance,
198 IN PULONG RebalanceListEntries)
199 {
200 DPRINT1("USB2_PromotePeriods: UNIMPLEMENTED. FIXME\n");
201 ASSERT(FALSE);
202 return FALSE;
203 }
204
205 VOID
206 NTAPI
207 USBPORT_UpdateAllocatedBwTt(IN PUSB2_TT_EXTENSION TtExtension)
208 {
209 ULONG BusBandwidth;
210 ULONG NewBusBandwidth;
211 ULONG MaxBusBandwidth = 0;
212 ULONG MinBusBandwidth;
213 ULONG ix;
214
215 DPRINT("USBPORT_UpdateAllocatedBwTt: TtExtension - %p\n", TtExtension);
216
217 BusBandwidth = TtExtension->BusBandwidth;
218 MinBusBandwidth = BusBandwidth;
219
220 for (ix = 0; ix < USB2_FRAMES; ix++)
221 {
222 NewBusBandwidth = BusBandwidth - TtExtension->Bandwidth[ix];
223
224 if (NewBusBandwidth > MaxBusBandwidth)
225 MaxBusBandwidth = NewBusBandwidth;
226
227 if (NewBusBandwidth < MinBusBandwidth)
228 MinBusBandwidth = NewBusBandwidth;
229 }
230
231 TtExtension->MaxBandwidth = MaxBusBandwidth;
232
233 if (MinBusBandwidth == BusBandwidth)
234 TtExtension->MinBandwidth = 0;
235 else
236 TtExtension->MinBandwidth = MinBusBandwidth;
237 }
238
239 BOOLEAN
240 NTAPI
241 USBPORT_AllocateBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
242 IN PUSBPORT_ENDPOINT Endpoint)
243 {
244 PUSBPORT_DEVICE_EXTENSION FdoExtension;
245 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
246 PUSB2_TT_EXTENSION TtExtension;
247 ULONG TransferType;
248 PUSB2_REBALANCE Rebalance;
249 LIST_ENTRY RebalanceList;
250 ULONG RebalanceListEntries;
251 PUSB2_TT_ENDPOINT TtEndpoint;
252 PUSB2_TT_ENDPOINT RebalanceTtEndpoint;
253
254 PUSB2_TT Tt;
255 USB_DEVICE_SPEED DeviceSpeed;
256 ULONG Period;
257
258 ULONG ix;
259 BOOLEAN Direction;
260 BOOLEAN Result;
261
262 DPRINT("USBPORT_AllocateBandwidthUSB2: FdoDevice - %p, Endpoint - %p\n",
263 FdoDevice,
264 Endpoint);
265
266 EndpointProperties = &Endpoint->EndpointProperties;
267 EndpointProperties->ScheduleOffset = 0;
268
269 if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
270 {
271 DPRINT("USBPORT_AllocateBandwidthUSB2: ENDPOINT_FLAG_ROOTHUB_EP0\n");
272 return TRUE;
273 }
274
275 FdoExtension = FdoDevice->DeviceExtension;
276
277 TransferType = EndpointProperties->TransferType;
278 DPRINT("USBPORT_AllocateBandwidthUSB2: TransferType - %X\n", TransferType);
279
280 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
281 TransferType == USBPORT_TRANSFER_TYPE_BULK)
282 {
283 return TRUE;
284 }
285
286 if (Endpoint->TtExtension)
287 TtExtension = Endpoint->TtExtension;
288 else
289 TtExtension = NULL;
290
291 InitializeListHead(&RebalanceList);
292
293 Rebalance = ExAllocatePoolWithTag(NonPagedPool,
294 sizeof(USB2_REBALANCE),
295 USB_PORT_TAG);
296
297 DPRINT("USBPORT_AllocateBandwidthUSB2: Rebalance - %p, TtExtension - %p\n",
298 Rebalance,
299 TtExtension);
300
301 if (Rebalance)
302 {
303 RtlZeroMemory(Rebalance, sizeof(USB2_REBALANCE));
304
305 TtEndpoint = Endpoint->TtEndpoint;
306 TtEndpoint->Endpoint = Endpoint;
307
308 Direction = EndpointProperties->Direction == USBPORT_TRANSFER_DIRECTION_OUT;
309 DeviceSpeed = EndpointProperties->DeviceSpeed;
310
311 switch (DeviceSpeed)
312 {
313 case UsbLowSpeed:
314 case UsbFullSpeed:
315 {
316 Tt = &TtExtension->Tt;
317 Period = USB2_FRAMES;
318
319 while (Period && Period > EndpointProperties->Period);
320 {
321 Period >>= 1;
322 }
323
324 DPRINT("USBPORT_AllocateBandwidthUSB2: Period - %X\n", Period);
325 break;
326 }
327
328 case UsbHighSpeed:
329 {
330 Tt = &FdoExtension->Usb2Extension->HcTt;
331 Period = EndpointProperties->Period;
332
333 if (EndpointProperties->Period > USB2_MAX_MICROFRAMES)
334 Period = USB2_MAX_MICROFRAMES;
335
336 break;
337 }
338
339 default:
340 {
341 DPRINT1("USBPORT_AllocateBandwidthUSB2: DeviceSpeed - %X!\n", DeviceSpeed);
342 DbgBreakPoint();
343 Tt = &TtExtension->Tt;
344 break;
345 }
346 }
347
348 USB2_InitTtEndpoint(TtEndpoint,
349 TransferType,
350 Direction,
351 DeviceSpeed,
352 Period,
353 EndpointProperties->MaxPacketSize,
354 Tt);
355
356 RebalanceListEntries = USB2_FRAMES - 2;
357
358 Result = USB2_AllocateTimeForEndpoint(TtEndpoint,
359 Rebalance,
360 &RebalanceListEntries);
361
362 if (Result)
363 {
364 Result = USB2_PromotePeriods(TtEndpoint,
365 Rebalance,
366 &RebalanceListEntries);
367 }
368
369 RebalanceListEntries = 0;
370
371 for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
372 {
373 RebalanceListEntries = ix + 1;
374 }
375 }
376 else
377 {
378 RebalanceListEntries = 0;
379 Result = FALSE;
380 }
381
382 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceListEntries - %X, Result - %X\n",
383 RebalanceListEntries,
384 Result);
385
386 for (ix = 0; ix < RebalanceListEntries; ix++)
387 {
388 DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceEndpoint[%X] - %X\n",
389 ix,
390 Rebalance->RebalanceEndpoint[ix]);
391
392 RebalanceTtEndpoint = Rebalance->RebalanceEndpoint[ix];
393
394 InsertTailList(&RebalanceList,
395 &RebalanceTtEndpoint->Endpoint->RebalanceLink);
396 }
397
398 if (Rebalance)
399 ExFreePool(Rebalance);
400
401 if (Result)
402 {
403 DPRINT1("USBPORT_AllocateBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
404 ASSERT(FALSE);
405 }
406
407 //USB2_Rebalance(FdoDevice, &RebalanceList);
408
409 if (!TtExtension)
410 {
411 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
412 return Result;
413 }
414
415 for (ix = 0; ix < USB2_FRAMES; ix++)
416 {
417 FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
418 }
419
420 USBPORT_UpdateAllocatedBwTt(TtExtension);
421
422 for (ix = 0; ix < USB2_FRAMES; ix++)
423 {
424 FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth;
425 }
426
427 DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
428
429 return Result;
430 }
431
432 VOID
433 NTAPI
434 USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
435 IN PUSBPORT_ENDPOINT Endpoint)
436 {
437 DPRINT1("USBPORT_FreeBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
438 }
439
440 VOID
441 NTAPI
442 USB2_InitTT(IN PUSB2_HC_EXTENSION HcExtension,
443 IN PUSB2_TT Tt)
444 {
445 ULONG ix;
446 ULONG jx;
447
448 DPRINT("USB2_InitTT: HcExtension - %p, Tt - %p\n", HcExtension, Tt);
449
450 Tt->HcExtension = HcExtension;
451 Tt->DelayTime = 1;
452 Tt->MaxTime = USB2_FS_MAX_PERIODIC_ALLOCATION;
453
454 for (ix = 0; ix < USB2_FRAMES; ix++)
455 {
456 Tt->FrameBudget[ix].TimeUsed = USB2_MAX_MICROFRAMES;
457 Tt->FrameBudget[ix].AltEndpoint = NULL;
458
459 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
460 {
461 Tt->TimeCS[ix][jx] = 0;
462 Tt->NumStartSplits[ix][jx] = 0;
463 }
464
465 Tt->FrameBudget[ix].IsoEndpoint = &Tt->IsoEndpoint[ix];
466
467 USB2_InitTtEndpoint(&Tt->IsoEndpoint[ix],
468 USBPORT_TRANSFER_TYPE_ISOCHRONOUS,
469 USBPORT_TRANSFER_DIRECTION_OUT,
470 UsbFullSpeed,
471 USB2_FRAMES,
472 0,
473 Tt);
474
475 Tt->IsoEndpoint[ix].ActualPeriod = USB2_FRAMES;
476 Tt->IsoEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
477 Tt->IsoEndpoint[ix].StartFrame = ix;
478 Tt->IsoEndpoint[ix].StartMicroframe = 0xFF;
479
480 Tt->FrameBudget[ix].IntEndpoint = &Tt->IntEndpoint[ix];
481
482 USB2_InitTtEndpoint(&Tt->IntEndpoint[ix],
483 USBPORT_TRANSFER_TYPE_INTERRUPT,
484 USBPORT_TRANSFER_DIRECTION_OUT,
485 UsbFullSpeed,
486 USB2_FRAMES,
487 0,
488 Tt);
489
490 Tt->IntEndpoint[ix].ActualPeriod = USB2_FRAMES;
491 Tt->IntEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
492 Tt->IntEndpoint[ix].StartFrame = ix;
493 Tt->IntEndpoint[ix].StartMicroframe = 0xFF;
494 }
495 }
496
497 VOID
498 NTAPI
499 USB2_InitController(IN PUSB2_HC_EXTENSION HcExtension)
500 {
501 ULONG ix;
502 ULONG jx;
503
504 DPRINT("USB2_InitController: HcExtension - %p\n", HcExtension);
505
506 HcExtension->MaxHsBusAllocation = USB2_MAX_MICROFRAME_ALLOCATION;
507
508 for (ix = 0; ix < USB2_FRAMES; ix++)
509 {
510 for (jx = 0; jx < USB2_MICROFRAMES; jx++)
511 {
512 HcExtension->TimeUsed[ix][jx] = 0;
513 }
514 }
515
516 HcExtension->HcDelayTime = USB2_CONTROLLER_DELAY;
517
518 USB2_InitTT(HcExtension, &HcExtension->HcTt);
519 }