[USBPORT] Use min() macro.
[reactos.git] / drivers / usb / usbport / endpoint.c
1 /*
2 * PROJECT: ReactOS USB Port Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: USBPort endpoint 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 #define NDEBUG_USBPORT_CORE
14 #include "usbdebug.h"
15
16 ULONG
17 NTAPI
18 USBPORT_CalculateUsbBandwidth(IN PDEVICE_OBJECT FdoDevice,
19 IN PUSBPORT_ENDPOINT Endpoint)
20 {
21 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
22 ULONG Bandwidth;
23 ULONG Overhead;
24
25 DPRINT("USBPORT_CalculateUsbBandwidth ... \n");
26
27 EndpointProperties = &Endpoint->EndpointProperties;
28
29 switch (EndpointProperties->TransferType)
30 {
31 case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
32 Overhead = USB2_FS_ISOCHRONOUS_OVERHEAD;
33 break;
34
35 case USBPORT_TRANSFER_TYPE_INTERRUPT:
36 Overhead = USB2_FS_INTERRUPT_OVERHEAD;
37 break;
38
39 default: //USBPORT_TRANSFER_TYPE_CONTROL or USBPORT_TRANSFER_TYPE_BULK
40 Overhead = 0;
41 break;
42 }
43
44 if (Overhead == 0)
45 {
46 Bandwidth = 0;
47 }
48 else
49 {
50 Bandwidth = (EndpointProperties->TotalMaxPacketSize + Overhead) * 8 * 7 / 6;
51 }
52
53 if (EndpointProperties->DeviceSpeed == UsbLowSpeed)
54 {
55 Bandwidth *= 8;
56 }
57
58 return Bandwidth;
59 }
60
61 BOOLEAN
62 NTAPI
63 USBPORT_AllocateBandwidth(IN PDEVICE_OBJECT FdoDevice,
64 IN PUSBPORT_ENDPOINT Endpoint)
65 {
66 PUSBPORT_DEVICE_EXTENSION FdoExtension;
67 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
68 ULONG TransferType;
69 ULONG TotalBusBandwidth;
70 ULONG EndpointBandwidth;
71 ULONG MinBandwidth;
72 PULONG Bandwidth;
73 ULONG MaxBandwidth = 0;
74 ULONG ix;
75 ULONG Offset;
76 LONG ScheduleOffset = -1;
77 ULONG Period;
78 ULONG Factor;
79 UCHAR Bit;
80
81 DPRINT("USBPORT_AllocateBandwidth: FdoDevice - %p, Endpoint - %p\n",
82 FdoDevice,
83 Endpoint);
84
85 FdoExtension = FdoDevice->DeviceExtension;
86 EndpointProperties = &Endpoint->EndpointProperties;
87 TransferType = EndpointProperties->TransferType;
88
89 if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
90 TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
91 Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
92 {
93 EndpointProperties->ScheduleOffset = 0;
94 return TRUE;
95 }
96
97 TotalBusBandwidth = FdoExtension->TotalBusBandwidth;
98 EndpointBandwidth = EndpointProperties->UsbBandwidth;
99 Period = EndpointProperties->Period;
100 Factor = USB2_FRAMES / Period;
101 ASSERT(Factor);
102
103 for (Offset = 0; Offset < Period; Offset++)
104 {
105 MinBandwidth = TotalBusBandwidth;
106 Bandwidth = &FdoExtension->Bandwidth[Offset * Factor];
107
108 for (ix = 1; *Bandwidth >= EndpointBandwidth; ix++)
109 {
110 MinBandwidth = min(MinBandwidth, *Bandwidth);
111
112 Bandwidth++;
113
114 if (Factor <= ix)
115 {
116 if (MinBandwidth > MaxBandwidth)
117 {
118 MaxBandwidth = MinBandwidth;
119 ScheduleOffset = Offset;
120
121 DPRINT("USBPORT_AllocateBandwidth: ScheduleOffset - %X\n",
122 ScheduleOffset);
123 }
124
125 break;
126 }
127 }
128 }
129
130 DPRINT("USBPORT_AllocateBandwidth: ScheduleOffset - %X\n", ScheduleOffset);
131
132 if (ScheduleOffset != -1)
133 {
134 EndpointProperties->ScheduleOffset = ScheduleOffset;
135
136 Bandwidth = &FdoExtension->Bandwidth[ScheduleOffset * Factor];
137
138 for (Factor = USB2_FRAMES / Period; Factor; Factor--)
139 {
140 FdoExtension->Bandwidth[ScheduleOffset * Factor] -= EndpointBandwidth;
141 }
142
143 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
144 {
145 for (Bit = 0x80; Bit != 0; Bit >>= 1)
146 {
147 if ((Period & Bit) != 0)
148 {
149 Period = Bit;
150 break;
151 }
152 }
153
154 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedInterrupt_XXms\n");
155 }
156 else
157 {
158 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedIso\n");
159 }
160 }
161
162 DPRINT("USBPORT_AllocateBandwidth: FIXME USBPORT_UpdateAllocatedBw\n");
163
164 DPRINT("USBPORT_AllocateBandwidth: ScheduleOffset - %X\n", ScheduleOffset);
165 return ScheduleOffset != -1;
166 }
167
168 VOID
169 NTAPI
170 USBPORT_FreeBandwidth(IN PDEVICE_OBJECT FdoDevice,
171 IN PUSBPORT_ENDPOINT Endpoint)
172 {
173 PUSBPORT_DEVICE_EXTENSION FdoExtension;
174 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
175 ULONG TransferType;
176 ULONG Offset;
177 ULONG EndpointBandwidth;
178 ULONG Period;
179 ULONG Factor;
180 UCHAR Bit;
181
182 DPRINT("USBPORT_FreeBandwidth: FdoDevice - %p, Endpoint - %p\n",
183 FdoDevice,
184 Endpoint);
185
186 FdoExtension = FdoDevice->DeviceExtension;
187
188 EndpointProperties = &Endpoint->EndpointProperties;
189 TransferType = EndpointProperties->TransferType;
190
191 if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
192 TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
193 (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
194 {
195 return;
196 }
197
198 Offset = Endpoint->EndpointProperties.ScheduleOffset;
199 EndpointBandwidth = Endpoint->EndpointProperties.UsbBandwidth;
200 Period = Endpoint->EndpointProperties.Period;
201
202 ASSERT(USB2_FRAMES / Period);
203
204 for (Factor = USB2_FRAMES / Period; Factor; Factor--)
205 {
206 FdoExtension->Bandwidth[Offset * Factor] += EndpointBandwidth;
207 }
208
209 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
210 {
211 for (Bit = 0x80; Bit != 0; Bit >>= 1)
212 {
213 if ((Period & Bit) != 0)
214 {
215 Period = Bit;
216 break;
217 }
218 }
219
220 ASSERT(Period != 0);
221
222 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedInterrupt_XXms\n");
223 }
224 else
225 {
226 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedIso\n");
227 }
228
229 DPRINT1("USBPORT_FreeBandwidth: FIXME USBPORT_UpdateAllocatedBw\n");
230 }
231
232 UCHAR
233 NTAPI
234 USBPORT_NormalizeHsInterval(UCHAR Interval)
235 {
236 UCHAR interval;
237
238 DPRINT("USBPORT_NormalizeHsInterval: Interval - %x\n", Interval);
239
240 interval = Interval;
241
242 if (Interval)
243 interval = Interval - 1;
244
245 if (interval > 5)
246 interval = 5;
247
248 return 1 << interval;
249 }
250
251 BOOLEAN
252 NTAPI
253 USBPORT_EndpointHasQueuedTransfers(IN PDEVICE_OBJECT FdoDevice,
254 IN PUSBPORT_ENDPOINT Endpoint,
255 IN PULONG TransferCount)
256 {
257 PLIST_ENTRY Entry;
258 PUSBPORT_TRANSFER Transfer;
259 BOOLEAN Result = FALSE;
260
261 DPRINT_CORE("USBPORT_EndpointHasQueuedTransfers: ... \n");
262
263 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
264
265 if (!IsListEmpty(&Endpoint->PendingTransferList))
266 Result = TRUE;
267
268 if (!IsListEmpty(&Endpoint->TransferList))
269 {
270 Result = TRUE;
271
272 if (TransferCount)
273 {
274 *TransferCount = 0;
275
276 for (Entry = Endpoint->TransferList.Flink;
277 Entry && Entry != &Endpoint->TransferList;
278 Entry = Transfer->TransferLink.Flink)
279 {
280 Transfer = CONTAINING_RECORD(Entry,
281 USBPORT_TRANSFER,
282 TransferLink);
283
284 if (Transfer->Flags & TRANSFER_FLAG_SUBMITED)
285 {
286 ++*TransferCount;
287 }
288 }
289 }
290 }
291
292 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
293
294 return Result;
295 }
296
297 VOID
298 NTAPI
299 USBPORT_NukeAllEndpoints(IN PDEVICE_OBJECT FdoDevice)
300 {
301 PUSBPORT_DEVICE_EXTENSION FdoExtension;
302 PLIST_ENTRY EndpointList;
303 PUSBPORT_ENDPOINT Endpoint;
304 KIRQL OldIrql;
305
306 DPRINT("USBPORT_NukeAllEndpoints \n");
307
308 FdoExtension = FdoDevice->DeviceExtension;
309
310 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
311
312 EndpointList = FdoExtension->EndpointList.Flink;
313
314 while (EndpointList && (EndpointList != &FdoExtension->EndpointList))
315 {
316 Endpoint = CONTAINING_RECORD(EndpointList,
317 USBPORT_ENDPOINT,
318 EndpointLink);
319
320 if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
321 Endpoint->Flags |= ENDPOINT_FLAG_NUKE;
322
323 EndpointList = Endpoint->EndpointLink.Flink;
324 }
325
326 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
327 }
328
329 ULONG
330 NTAPI
331 USBPORT_GetEndpointState(IN PUSBPORT_ENDPOINT Endpoint)
332 {
333 ULONG State;
334
335 //DPRINT("USBPORT_GetEndpointState \n");
336
337 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
338
339 if (Endpoint->StateLast != Endpoint->StateNext)
340 {
341 State = USBPORT_ENDPOINT_UNKNOWN;
342 }
343 else
344 {
345 State = Endpoint->StateLast;
346 }
347
348 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
349
350 if (State != USBPORT_ENDPOINT_ACTIVE)
351 {
352 DPRINT("USBPORT_GetEndpointState: Endpoint - %p, State - %x\n",
353 Endpoint,
354 State);
355 }
356
357 return State;
358 }
359
360 VOID
361 NTAPI
362 USBPORT_SetEndpointState(IN PUSBPORT_ENDPOINT Endpoint,
363 IN ULONG State)
364 {
365 PDEVICE_OBJECT FdoDevice;
366 PUSBPORT_DEVICE_EXTENSION FdoExtension;
367 PUSBPORT_REGISTRATION_PACKET Packet;
368 KIRQL OldIrql;
369
370 DPRINT("USBPORT_SetEndpointState: Endpoint - %p, State - %x\n",
371 Endpoint,
372 State);
373
374 FdoDevice = Endpoint->FdoDevice;
375 FdoExtension = FdoDevice->DeviceExtension;
376 Packet = &FdoExtension->MiniPortInterface->Packet;
377
378 KeAcquireSpinLock(&Endpoint->StateChangeSpinLock,
379 &Endpoint->EndpointStateOldIrql);
380
381 if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
382 {
383 if (Endpoint->Flags & ENDPOINT_FLAG_NUKE)
384 {
385 Endpoint->StateLast = State;
386 Endpoint->StateNext = State;
387
388 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
389 Endpoint->EndpointStateOldIrql);
390
391 USBPORT_InvalidateEndpointHandler(FdoDevice,
392 Endpoint,
393 INVALIDATE_ENDPOINT_WORKER_THREAD);
394 return;
395 }
396
397 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
398 Endpoint->EndpointStateOldIrql);
399
400 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
401 Packet->SetEndpointState(FdoExtension->MiniPortExt,
402 Endpoint + 1,
403 State);
404 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
405
406 Endpoint->StateNext = State;
407
408 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
409 Endpoint->FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt);
410 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
411
412 ExInterlockedInsertTailList(&FdoExtension->EpStateChangeList,
413 &Endpoint->StateChangeLink,
414 &FdoExtension->EpStateChangeSpinLock);
415
416 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
417 Packet->InterruptNextSOF(FdoExtension->MiniPortExt);
418 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
419 }
420 else
421 {
422 Endpoint->StateLast = State;
423 Endpoint->StateNext = State;
424
425 if (State == USBPORT_ENDPOINT_REMOVE)
426 {
427 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
428 Endpoint->EndpointStateOldIrql);
429
430 USBPORT_InvalidateEndpointHandler(FdoDevice,
431 Endpoint,
432 INVALIDATE_ENDPOINT_WORKER_THREAD);
433 return;
434 }
435
436 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
437 Endpoint->EndpointStateOldIrql);
438 }
439 }
440
441 VOID
442 NTAPI
443 USBPORT_AddPipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
444 IN PUSBPORT_PIPE_HANDLE PipeHandle)
445 {
446 DPRINT("USBPORT_AddPipeHandle: DeviceHandle - %p, PipeHandle - %p\n",
447 DeviceHandle,
448 PipeHandle);
449
450 InsertTailList(&DeviceHandle->PipeHandleList, &PipeHandle->PipeLink);
451 }
452
453 VOID
454 NTAPI
455 USBPORT_RemovePipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
456 IN PUSBPORT_PIPE_HANDLE PipeHandle)
457 {
458 DPRINT("USBPORT_RemovePipeHandle: PipeHandle - %p\n", PipeHandle);
459
460 RemoveEntryList(&PipeHandle->PipeLink);
461
462 PipeHandle->PipeLink.Flink = NULL;
463 PipeHandle->PipeLink.Blink = NULL;
464 }
465
466 BOOLEAN
467 NTAPI
468 USBPORT_ValidatePipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
469 IN PUSBPORT_PIPE_HANDLE PipeHandle)
470 {
471 PLIST_ENTRY HandleList;
472 PUSBPORT_PIPE_HANDLE CurrentHandle;
473
474 //DPRINT("USBPORT_ValidatePipeHandle: DeviceHandle - %p, PipeHandle - %p\n",
475 // DeviceHandle,
476 // PipeHandle);
477
478 HandleList = DeviceHandle->PipeHandleList.Flink;
479
480 while (HandleList != &DeviceHandle->PipeHandleList)
481 {
482 CurrentHandle = CONTAINING_RECORD(HandleList,
483 USBPORT_PIPE_HANDLE,
484 PipeLink);
485
486 HandleList = HandleList->Flink;
487
488 if (CurrentHandle == PipeHandle)
489 return TRUE;
490 }
491
492 return FALSE;
493 }
494
495 BOOLEAN
496 NTAPI
497 USBPORT_DeleteEndpoint(IN PDEVICE_OBJECT FdoDevice,
498 IN PUSBPORT_ENDPOINT Endpoint)
499 {
500 PUSBPORT_DEVICE_EXTENSION FdoExtension;
501 BOOLEAN Result;
502 KIRQL OldIrql;
503
504 DPRINT1("USBPORT_DeleteEndpoint: Endpoint - %p\n", Endpoint);
505
506 FdoExtension = FdoDevice->DeviceExtension;
507
508 if ((Endpoint->WorkerLink.Flink && Endpoint->WorkerLink.Blink) ||
509 Endpoint->LockCounter != -1)
510 {
511 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
512
513 ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
514 &Endpoint->CloseLink,
515 &FdoExtension->EndpointClosedSpinLock);
516
517 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
518
519 Result = FALSE;
520 }
521 else
522 {
523 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
524
525 RemoveEntryList(&Endpoint->EndpointLink);
526 Endpoint->EndpointLink.Flink = NULL;
527 Endpoint->EndpointLink.Blink = NULL;
528
529 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
530
531 MiniportCloseEndpoint(FdoDevice, Endpoint);
532
533 if (Endpoint->HeaderBuffer)
534 {
535 USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer);
536 }
537
538 ExFreePoolWithTag(Endpoint, USB_PORT_TAG);
539
540 Result = TRUE;
541 }
542
543 return Result;
544 }
545
546 VOID
547 NTAPI
548 MiniportCloseEndpoint(IN PDEVICE_OBJECT FdoDevice,
549 IN PUSBPORT_ENDPOINT Endpoint)
550 {
551 PUSBPORT_DEVICE_EXTENSION FdoExtension;
552 PUSBPORT_REGISTRATION_PACKET Packet;
553 BOOLEAN IsDoDisablePeriodic;
554 ULONG TransferType;
555 KIRQL OldIrql;
556
557 DPRINT("MiniportCloseEndpoint: Endpoint - %p\n", Endpoint);
558
559 FdoExtension = FdoDevice->DeviceExtension;
560 Packet = &FdoExtension->MiniPortInterface->Packet;
561
562 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
563
564 if (Endpoint->Flags & ENDPOINT_FLAG_OPENED)
565 {
566 TransferType = Endpoint->EndpointProperties.TransferType;
567
568 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT ||
569 TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
570 {
571 --FdoExtension->PeriodicEndpoints;
572 }
573
574 IsDoDisablePeriodic = FdoExtension->PeriodicEndpoints == 0;
575
576 Packet->CloseEndpoint(FdoExtension->MiniPortExt,
577 Endpoint + 1,
578 IsDoDisablePeriodic);
579
580 Endpoint->Flags &= ~ENDPOINT_FLAG_OPENED;
581 Endpoint->Flags |= ENDPOINT_FLAG_CLOSED;
582 }
583
584 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
585 }
586
587 VOID
588 NTAPI
589 USBPORT_ClosePipe(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
590 IN PDEVICE_OBJECT FdoDevice,
591 IN PUSBPORT_PIPE_HANDLE PipeHandle)
592 {
593 PUSBPORT_DEVICE_EXTENSION FdoExtension;
594 PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
595 PUSBPORT_ENDPOINT Endpoint;
596 PUSBPORT_REGISTRATION_PACKET Packet;
597 PUSB2_TT_EXTENSION TtExtension;
598 ULONG ix;
599 BOOLEAN IsReady;
600 KIRQL OldIrql;
601
602 DPRINT1("USBPORT_ClosePipe \n");
603
604 FdoExtension = FdoDevice->DeviceExtension;
605
606 if (PipeHandle->Flags & PIPE_HANDLE_FLAG_CLOSED)
607 return;
608
609 USBPORT_RemovePipeHandle(DeviceHandle, PipeHandle);
610
611 PipeHandle->Flags |= PIPE_HANDLE_FLAG_CLOSED;
612
613 if (PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE)
614 {
615 PipeHandle->Flags &= ~PIPE_HANDLE_FLAG_NULL_PACKET_SIZE;
616 return;
617 }
618
619 Endpoint = PipeHandle->Endpoint;
620
621 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
622
623 if ((Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) &&
624 (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT))
625 {
626 PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
627 PdoExtension->Endpoint = NULL;
628 }
629
630 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
631
632 while (TRUE)
633 {
634 IsReady = TRUE;
635
636 KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
637 &Endpoint->EndpointOldIrql);
638
639 if (!IsListEmpty(&Endpoint->PendingTransferList))
640 IsReady = FALSE;
641
642 if (!IsListEmpty(&Endpoint->TransferList))
643 IsReady = FALSE;
644
645 if (!IsListEmpty(&Endpoint->CancelList))
646 IsReady = FALSE;
647
648 if (!IsListEmpty(&Endpoint->AbortList))
649 IsReady = FALSE;
650
651 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
652 if (Endpoint->StateLast != Endpoint->StateNext)
653 IsReady = FALSE;
654 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
655
656 KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
657 Endpoint->EndpointOldIrql);
658
659 if (InterlockedIncrement(&Endpoint->LockCounter))
660 IsReady = FALSE;
661 InterlockedDecrement(&Endpoint->LockCounter);
662
663 if (IsReady == TRUE)
664 break;
665
666 USBPORT_Wait(FdoDevice, 1);
667 }
668
669 Endpoint->DeviceHandle = NULL;
670 Packet = &FdoExtension->MiniPortInterface->Packet;
671
672 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
673 {
674 USBPORT_FreeBandwidthUSB2(FdoDevice, Endpoint);
675
676 KeAcquireSpinLock(&FdoExtension->TtSpinLock, &OldIrql);
677
678 TtExtension = Endpoint->TtExtension;
679 DPRINT1("USBPORT_ClosePipe: TtExtension - %p\n", TtExtension);
680
681 if (TtExtension)
682 {
683 RemoveEntryList(&Endpoint->TtLink);
684
685 Endpoint->TtLink.Flink = NULL;
686 Endpoint->TtLink.Blink = NULL;
687
688 if (TtExtension->Flags & USB2_TT_EXTENSION_FLAG_DELETED)
689 {
690 if (IsListEmpty(&TtExtension->EndpointList))
691 {
692 USBPORT_UpdateAllocatedBwTt(TtExtension);
693
694 for (ix = 0; ix < USB2_FRAMES; ix++)
695 {
696 FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
697 }
698
699 DPRINT1("USBPORT_ClosePipe: ExFreePoolWithTag TtExtension - %p\n", TtExtension);
700 ExFreePoolWithTag(TtExtension, USB_PORT_TAG);
701 }
702 }
703 }
704
705 KeReleaseSpinLock(&FdoExtension->TtSpinLock, OldIrql);
706 }
707 else
708 {
709 USBPORT_FreeBandwidth(FdoDevice, Endpoint);
710 }
711
712 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
713 USBPORT_SetEndpointState(Endpoint, USBPORT_ENDPOINT_REMOVE);
714 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
715
716 USBPORT_SignalWorkerThread(FdoDevice);
717 }
718
719 MPSTATUS
720 NTAPI
721 MiniportOpenEndpoint(IN PDEVICE_OBJECT FdoDevice,
722 IN PUSBPORT_ENDPOINT Endpoint)
723 {
724 PUSBPORT_DEVICE_EXTENSION FdoExtension;
725 PUSBPORT_REGISTRATION_PACKET Packet;
726 KIRQL OldIrql;
727 ULONG TransferType;
728 MPSTATUS MpStatus;
729
730 DPRINT("MiniportOpenEndpoint: Endpoint - %p\n", Endpoint);
731
732 FdoExtension = FdoDevice->DeviceExtension;
733 Packet = &FdoExtension->MiniPortInterface->Packet;
734
735 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
736
737 Endpoint->Flags &= ~ENDPOINT_FLAG_CLOSED;
738
739 MpStatus = Packet->OpenEndpoint(FdoExtension->MiniPortExt,
740 &Endpoint->EndpointProperties,
741 Endpoint + 1);
742
743 if (!MpStatus)
744 {
745 TransferType = Endpoint->EndpointProperties.TransferType;
746
747 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT ||
748 TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
749 {
750 ++FdoExtension->PeriodicEndpoints;
751 }
752
753 Endpoint->Flags |= ENDPOINT_FLAG_OPENED;
754 }
755
756 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
757 return MpStatus;
758 }
759
760 NTSTATUS
761 NTAPI
762 USBPORT_OpenPipe(IN PDEVICE_OBJECT FdoDevice,
763 IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
764 IN PUSBPORT_PIPE_HANDLE PipeHandle,
765 IN OUT PUSBD_STATUS UsbdStatus)
766 {
767 PUSBPORT_DEVICE_EXTENSION FdoExtension;
768 PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
769 PUSBPORT_REGISTRATION_PACKET Packet;
770 ULONG EndpointSize;
771 PUSBPORT_ENDPOINT Endpoint;
772 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
773 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
774 UCHAR Direction;
775 UCHAR Interval;
776 UCHAR Period;
777 USBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements = {0};
778 PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer;
779 MPSTATUS MpStatus;
780 USBD_STATUS USBDStatus;
781 NTSTATUS Status;
782 KIRQL OldIrql;
783 USHORT MaxPacketSize;
784 USHORT AdditionalTransaction;
785 BOOLEAN IsAllocatedBandwidth;
786
787 DPRINT1("USBPORT_OpenPipe: DeviceHandle - %p, FdoDevice - %p, PipeHandle - %p\n",
788 DeviceHandle,
789 FdoDevice,
790 PipeHandle);
791
792 FdoExtension = FdoDevice->DeviceExtension;
793 Packet = &FdoExtension->MiniPortInterface->Packet;
794
795 EndpointSize = sizeof(USBPORT_ENDPOINT) + Packet->MiniPortEndpointSize;
796
797 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
798 {
799 EndpointSize += sizeof(USB2_TT_ENDPOINT);
800 }
801
802 if (PipeHandle->EndpointDescriptor.wMaxPacketSize == 0)
803 {
804 USBPORT_AddPipeHandle(DeviceHandle, PipeHandle);
805
806 PipeHandle->Flags = (PipeHandle->Flags & ~PIPE_HANDLE_FLAG_CLOSED) |
807 PIPE_HANDLE_FLAG_NULL_PACKET_SIZE;
808
809 PipeHandle->Endpoint = (PUSBPORT_ENDPOINT)-1;
810
811 return STATUS_SUCCESS;
812 }
813
814 Endpoint = ExAllocatePoolWithTag(NonPagedPool, EndpointSize, USB_PORT_TAG);
815
816 if (!Endpoint)
817 {
818 DPRINT1("USBPORT_OpenPipe: Not allocated Endpoint!\n");
819 Status = STATUS_INSUFFICIENT_RESOURCES;
820 return Status;
821 }
822
823 RtlZeroMemory(Endpoint, EndpointSize);
824
825 Endpoint->FdoDevice = FdoDevice;
826 Endpoint->DeviceHandle = DeviceHandle;
827 Endpoint->LockCounter = -1;
828
829 Endpoint->TtExtension = DeviceHandle->TtExtension;
830
831 if (DeviceHandle->TtExtension)
832 {
833 ExInterlockedInsertTailList(&DeviceHandle->TtExtension->EndpointList,
834 &Endpoint->TtLink,
835 &FdoExtension->TtSpinLock);
836 }
837
838 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
839 {
840 Endpoint->TtEndpoint = (PUSB2_TT_ENDPOINT)((ULONG_PTR)Endpoint +
841 sizeof(USBPORT_ENDPOINT) +
842 Packet->MiniPortEndpointSize);
843 }
844 else
845 {
846 Endpoint->TtEndpoint = NULL;
847 }
848
849 KeInitializeSpinLock(&Endpoint->EndpointSpinLock);
850 KeInitializeSpinLock(&Endpoint->StateChangeSpinLock);
851
852 InitializeListHead(&Endpoint->PendingTransferList);
853 InitializeListHead(&Endpoint->TransferList);
854 InitializeListHead(&Endpoint->CancelList);
855 InitializeListHead(&Endpoint->AbortList);
856
857 EndpointProperties = &Endpoint->EndpointProperties;
858 EndpointDescriptor = &PipeHandle->EndpointDescriptor;
859
860 MaxPacketSize = EndpointDescriptor->wMaxPacketSize & 0x7FF;
861 AdditionalTransaction = (EndpointDescriptor->wMaxPacketSize >> 11) & 3;
862
863 EndpointProperties->DeviceAddress = DeviceHandle->DeviceAddress;
864 EndpointProperties->DeviceSpeed = DeviceHandle->DeviceSpeed;
865 EndpointProperties->Period = 0;
866 EndpointProperties->EndpointAddress = EndpointDescriptor->bEndpointAddress;
867 EndpointProperties->TransactionPerMicroframe = AdditionalTransaction + 1;
868 EndpointProperties->MaxPacketSize = MaxPacketSize;
869 EndpointProperties->TotalMaxPacketSize = MaxPacketSize *
870 (AdditionalTransaction + 1);
871
872 if (Endpoint->TtExtension)
873 {
874 EndpointProperties->HubAddr = Endpoint->TtExtension->DeviceAddress;
875 }
876 else
877 {
878 EndpointProperties->HubAddr = -1;
879 }
880
881 EndpointProperties->PortNumber = DeviceHandle->PortNumber;
882
883 switch (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK)
884 {
885 case USB_ENDPOINT_TYPE_CONTROL:
886 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_CONTROL;
887
888 if (EndpointProperties->EndpointAddress == 0)
889 {
890 EndpointProperties->MaxTransferSize = 0x1000; // OUT Ep0
891 }
892 else
893 {
894 EndpointProperties->MaxTransferSize = 0x10000;
895 }
896
897 break;
898
899 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
900 DPRINT1("USBPORT_OpenPipe: USB_ENDPOINT_TYPE_ISOCHRONOUS UNIMPLEMENTED. FIXME. \n");
901 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_ISOCHRONOUS;
902 EndpointProperties->MaxTransferSize = 0x1000000;
903 break;
904
905 case USB_ENDPOINT_TYPE_BULK:
906 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_BULK;
907 EndpointProperties->MaxTransferSize = 0x10000;
908 break;
909
910 case USB_ENDPOINT_TYPE_INTERRUPT:
911 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_INTERRUPT;
912 EndpointProperties->MaxTransferSize = 0x400;
913 break;
914 }
915
916 if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
917 {
918 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
919 {
920 Interval = USBPORT_NormalizeHsInterval(EndpointDescriptor->bInterval);
921 }
922 else
923 {
924 Interval = EndpointDescriptor->bInterval;
925 }
926
927 EndpointProperties->Period = ENDPOINT_INTERRUPT_32ms;
928
929 if (Interval && (Interval < USB2_FRAMES))
930 {
931 if ((EndpointProperties->DeviceSpeed != UsbLowSpeed) ||
932 (Interval >= ENDPOINT_INTERRUPT_8ms))
933 {
934 if (!(Interval & ENDPOINT_INTERRUPT_32ms))
935 {
936 Period = EndpointProperties->Period;
937
938 do
939 {
940 Period >>= 1;
941 }
942 while (!(Period & Interval));
943
944 EndpointProperties->Period = Period;
945 }
946 }
947 else
948 {
949 EndpointProperties->Period = ENDPOINT_INTERRUPT_8ms;
950 }
951 }
952 }
953
954 if (EndpointProperties->TransferType == USB_ENDPOINT_TYPE_ISOCHRONOUS)
955 {
956 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
957 {
958 EndpointProperties->Period =
959 USBPORT_NormalizeHsInterval(EndpointDescriptor->bInterval);
960 }
961 else
962 {
963 EndpointProperties->Period = ENDPOINT_INTERRUPT_1ms;
964 }
965 }
966
967 if ((DeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB) != 0)
968 {
969 Endpoint->Flags |= ENDPOINT_FLAG_ROOTHUB_EP0;
970 }
971
972 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
973 {
974 IsAllocatedBandwidth = USBPORT_AllocateBandwidthUSB2(FdoDevice, Endpoint);
975 }
976 else
977 {
978 EndpointProperties->UsbBandwidth = USBPORT_CalculateUsbBandwidth(FdoDevice,
979 Endpoint);
980
981 IsAllocatedBandwidth = USBPORT_AllocateBandwidth(FdoDevice, Endpoint);
982 }
983
984 if (!IsAllocatedBandwidth)
985 {
986 Status = USBPORT_USBDStatusToNtStatus(NULL, USBD_STATUS_NO_BANDWIDTH);
987
988 if (UsbdStatus)
989 {
990 *UsbdStatus = USBD_STATUS_NO_BANDWIDTH;
991 }
992
993 goto ExitWithError;
994 }
995
996 Direction = USB_ENDPOINT_DIRECTION_OUT(EndpointDescriptor->bEndpointAddress);
997 EndpointProperties->Direction = Direction;
998
999 if (DeviceHandle->IsRootHub)
1000 {
1001 Endpoint->EndpointWorker = 0; // USBPORT_RootHubEndpointWorker;
1002
1003 Endpoint->Flags |= ENDPOINT_FLAG_ROOTHUB_EP0;
1004
1005 Endpoint->StateLast = USBPORT_ENDPOINT_ACTIVE;
1006 Endpoint->StateNext = USBPORT_ENDPOINT_ACTIVE;
1007
1008 PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
1009
1010 if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
1011 {
1012 PdoExtension->Endpoint = Endpoint;
1013 }
1014
1015 USBDStatus = USBD_STATUS_SUCCESS;
1016 }
1017 else
1018 {
1019 Endpoint->EndpointWorker = 1; // USBPORT_DmaEndpointWorker;
1020
1021 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1022
1023 Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
1024 &Endpoint->EndpointProperties,
1025 &EndpointRequirements);
1026
1027 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1028
1029 if ((EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_BULK) ||
1030 (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT))
1031 {
1032 EndpointProperties->MaxTransferSize = EndpointRequirements.MaxTransferSize;
1033 }
1034
1035 if (EndpointRequirements.HeaderBufferSize)
1036 {
1037 HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice,
1038 EndpointRequirements.HeaderBufferSize);
1039 }
1040 else
1041 {
1042 HeaderBuffer = NULL;
1043 }
1044
1045 if (HeaderBuffer || (EndpointRequirements.HeaderBufferSize == 0))
1046 {
1047 Endpoint->HeaderBuffer = HeaderBuffer;
1048
1049 if (HeaderBuffer)
1050 {
1051 EndpointProperties->BufferVA = HeaderBuffer->VirtualAddress;
1052 EndpointProperties->BufferPA = HeaderBuffer->PhysicalAddress;
1053 EndpointProperties->BufferLength = HeaderBuffer->BufferLength; // BufferLength + LengthPadded;
1054 }
1055
1056 MpStatus = MiniportOpenEndpoint(FdoDevice, Endpoint);
1057
1058 Endpoint->Flags |= ENDPOINT_FLAG_DMA_TYPE;
1059 Endpoint->Flags |= ENDPOINT_FLAG_QUEUENE_EMPTY;
1060
1061 if (MpStatus == 0)
1062 {
1063 ULONG State;
1064
1065 KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
1066 &Endpoint->EndpointOldIrql);
1067
1068 Endpoint->StateLast = USBPORT_ENDPOINT_PAUSED;
1069 Endpoint->StateNext = USBPORT_ENDPOINT_PAUSED;
1070
1071 USBPORT_SetEndpointState(Endpoint, USBPORT_ENDPOINT_ACTIVE);
1072
1073 KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
1074 Endpoint->EndpointOldIrql);
1075
1076 while (TRUE)
1077 {
1078 KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
1079 &Endpoint->EndpointOldIrql);
1080
1081 State = USBPORT_GetEndpointState(Endpoint);
1082
1083 KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
1084 Endpoint->EndpointOldIrql);
1085
1086 if (State == USBPORT_ENDPOINT_ACTIVE)
1087 {
1088 break;
1089 }
1090
1091 USBPORT_Wait(FdoDevice, 1); // 1 msec.
1092 }
1093 }
1094 }
1095 else
1096 {
1097 MpStatus = MP_STATUS_NO_RESOURCES;
1098 Endpoint->HeaderBuffer = NULL;
1099 }
1100
1101 if (MpStatus)
1102 {
1103 USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
1104 }
1105 else
1106 {
1107 USBDStatus = USBD_STATUS_SUCCESS;
1108 }
1109 }
1110
1111 if (UsbdStatus)
1112 {
1113 *UsbdStatus = USBDStatus;
1114 }
1115
1116 Status = USBPORT_USBDStatusToNtStatus(NULL, USBDStatus);
1117
1118 if (NT_SUCCESS(Status))
1119 {
1120 USBPORT_AddPipeHandle(DeviceHandle, PipeHandle);
1121
1122 ExInterlockedInsertTailList(&FdoExtension->EndpointList,
1123 &Endpoint->EndpointLink,
1124 &FdoExtension->EndpointListSpinLock);
1125
1126 PipeHandle->Endpoint = Endpoint;
1127 PipeHandle->Flags &= ~PIPE_HANDLE_FLAG_CLOSED;
1128
1129 return Status;
1130 }
1131
1132 ExitWithError:
1133
1134 if (Endpoint)
1135 {
1136 if (IsAllocatedBandwidth)
1137 {
1138 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
1139 {
1140 USBPORT_FreeBandwidthUSB2(FdoDevice, Endpoint);
1141 }
1142 else
1143 {
1144 USBPORT_FreeBandwidth(FdoDevice, Endpoint);
1145 }
1146 }
1147
1148 if (Endpoint->TtExtension)
1149 {
1150 KeAcquireSpinLock(&FdoExtension->TtSpinLock, &OldIrql);
1151 RemoveEntryList(&Endpoint->TtLink);
1152 KeReleaseSpinLock(&FdoExtension->TtSpinLock, OldIrql);
1153 }
1154
1155 ExFreePoolWithTag(Endpoint, USB_PORT_TAG);
1156 }
1157
1158 DPRINT1("USBPORT_OpenPipe: Status - %lx\n", Status);
1159 return Status;
1160 }
1161
1162 NTSTATUS
1163 NTAPI
1164 USBPORT_ReopenPipe(IN PDEVICE_OBJECT FdoDevice,
1165 IN PUSBPORT_ENDPOINT Endpoint)
1166 {
1167 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1168 PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer;
1169 USBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements = {0};
1170 PUSBPORT_REGISTRATION_PACKET Packet;
1171 KIRQL MiniportOldIrql;
1172 NTSTATUS Status;
1173
1174 DPRINT1("USBPORT_ReopenPipe ... \n");
1175
1176 FdoExtension = FdoDevice->DeviceExtension;
1177 Packet = &FdoExtension->MiniPortInterface->Packet;
1178
1179 while (TRUE)
1180 {
1181 if (!InterlockedIncrement(&Endpoint->LockCounter))
1182 break;
1183
1184 InterlockedDecrement(&Endpoint->LockCounter);
1185 USBPORT_Wait(FdoDevice, 1);
1186 }
1187
1188 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql);
1189
1190 Packet->SetEndpointState(FdoExtension->MiniPortExt,
1191 Endpoint + 1,
1192 USBPORT_ENDPOINT_REMOVE);
1193
1194 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql);
1195
1196 USBPORT_Wait(FdoDevice, 2);
1197
1198 MiniportCloseEndpoint(FdoDevice, Endpoint);
1199
1200 RtlZeroMemory(Endpoint + 1,
1201 Packet->MiniPortEndpointSize);
1202
1203 if (Endpoint->HeaderBuffer)
1204 {
1205 USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer);
1206 Endpoint->HeaderBuffer = NULL;
1207 }
1208
1209 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql);
1210
1211 Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
1212 &Endpoint->EndpointProperties,
1213 &EndpointRequirements);
1214
1215 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql);
1216
1217 if (EndpointRequirements.HeaderBufferSize)
1218 {
1219 HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice,
1220 EndpointRequirements.HeaderBufferSize);
1221 }
1222 else
1223 {
1224 HeaderBuffer = NULL;
1225 }
1226
1227 if (HeaderBuffer || EndpointRequirements.HeaderBufferSize == 0)
1228 {
1229 Endpoint->HeaderBuffer = HeaderBuffer;
1230 Status = STATUS_SUCCESS;
1231 }
1232 else
1233 {
1234 Endpoint->HeaderBuffer = 0;
1235 Status = STATUS_INSUFFICIENT_RESOURCES;
1236 }
1237
1238 if (Endpoint->HeaderBuffer && HeaderBuffer)
1239 {
1240 Endpoint->EndpointProperties.BufferVA = HeaderBuffer->VirtualAddress;
1241 Endpoint->EndpointProperties.BufferPA = HeaderBuffer->PhysicalAddress;
1242 Endpoint->EndpointProperties.BufferLength = HeaderBuffer->BufferLength;
1243 }
1244
1245 if (NT_SUCCESS(Status))
1246 {
1247 MiniportOpenEndpoint(FdoDevice, Endpoint);
1248
1249 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1250 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1251
1252 if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE)
1253 {
1254 KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1255
1256 Packet->SetEndpointState(FdoExtension->MiniPortExt,
1257 Endpoint + 1,
1258 USBPORT_ENDPOINT_ACTIVE);
1259
1260 KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1261 }
1262
1263 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1264 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1265 }
1266
1267 InterlockedDecrement(&Endpoint->LockCounter);
1268
1269 return Status;
1270 }
1271
1272 VOID
1273 NTAPI
1274 USBPORT_FlushClosedEndpointList(IN PDEVICE_OBJECT FdoDevice)
1275 {
1276 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1277 KIRQL OldIrql;
1278 PLIST_ENTRY ClosedList;
1279 PUSBPORT_ENDPOINT Endpoint;
1280
1281 DPRINT("USBPORT_FlushClosedEndpointList: ... \n");
1282
1283 FdoExtension = FdoDevice->DeviceExtension;
1284
1285 KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql);
1286 ClosedList = &FdoExtension->EndpointClosedList;
1287
1288 while (!IsListEmpty(ClosedList))
1289 {
1290 Endpoint = CONTAINING_RECORD(ClosedList->Flink,
1291 USBPORT_ENDPOINT,
1292 CloseLink);
1293
1294 RemoveHeadList(ClosedList);
1295 Endpoint->CloseLink.Flink = NULL;
1296 Endpoint->CloseLink.Blink = NULL;
1297
1298 KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql);
1299
1300 USBPORT_DeleteEndpoint(FdoDevice, Endpoint);
1301
1302 KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql);
1303 }
1304
1305 KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql);
1306 }
1307
1308 VOID
1309 NTAPI
1310 USBPORT_InvalidateEndpointHandler(IN PDEVICE_OBJECT FdoDevice,
1311 IN PUSBPORT_ENDPOINT Endpoint,
1312 IN ULONG Type)
1313 {
1314 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1315 PUSBPORT_REGISTRATION_PACKET Packet;
1316 PLIST_ENTRY Entry;
1317 PLIST_ENTRY WorkerLink;
1318 PUSBPORT_ENDPOINT endpoint;
1319 KIRQL OldIrql;
1320 BOOLEAN IsAddEntry = FALSE;
1321
1322 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: Endpoint - %p, Type - %x\n",
1323 Endpoint,
1324 Type);
1325
1326 FdoExtension = FdoDevice->DeviceExtension;
1327 Packet = &FdoExtension->MiniPortInterface->Packet;
1328
1329 if (Endpoint)
1330 {
1331 WorkerLink = &Endpoint->WorkerLink;
1332 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
1333 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: KeAcquireSpinLock \n");
1334
1335 if ((!WorkerLink->Flink || !WorkerLink->Blink) &&
1336 !(Endpoint->Flags & ENDPOINT_FLAG_IDLE) &&
1337 USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_CLOSED)
1338 {
1339 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n");
1340 InsertTailList(&FdoExtension->WorkerList, WorkerLink);
1341 IsAddEntry = TRUE;
1342 }
1343
1344 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
1345
1346 if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
1347 Type = INVALIDATE_ENDPOINT_WORKER_THREAD;
1348 }
1349 else
1350 {
1351 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
1352
1353 Entry = &FdoExtension->EndpointList;
1354
1355 while (Entry && Entry != &FdoExtension->EndpointList)
1356 {
1357 endpoint = CONTAINING_RECORD(Entry,
1358 USBPORT_ENDPOINT,
1359 EndpointLink);
1360
1361 if (!endpoint->WorkerLink.Flink || !endpoint->WorkerLink.Blink)
1362 {
1363 if (!(endpoint->Flags & ENDPOINT_FLAG_IDLE) &&
1364 !(endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) &&
1365 USBPORT_GetEndpointState(endpoint) != USBPORT_ENDPOINT_CLOSED)
1366 {
1367 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n");
1368 InsertTailList(&FdoExtension->WorkerList, &endpoint->WorkerLink);
1369 IsAddEntry = TRUE;
1370 }
1371 }
1372
1373 Entry = endpoint->EndpointLink.Flink;
1374 }
1375
1376 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
1377 }
1378
1379 if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)
1380 {
1381 Type = INVALIDATE_ENDPOINT_WORKER_THREAD;
1382 }
1383 else if (IsAddEntry == FALSE && Type == INVALIDATE_ENDPOINT_INT_NEXT_SOF)
1384 {
1385 Type = INVALIDATE_ENDPOINT_ONLY;
1386 }
1387
1388 switch (Type)
1389 {
1390 case INVALIDATE_ENDPOINT_WORKER_THREAD:
1391 USBPORT_SignalWorkerThread(FdoDevice);
1392 break;
1393
1394 case INVALIDATE_ENDPOINT_WORKER_DPC:
1395 KeInsertQueueDpc(&FdoExtension->WorkerRequestDpc, NULL, NULL);
1396 break;
1397
1398 case INVALIDATE_ENDPOINT_INT_NEXT_SOF:
1399 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1400 Packet->InterruptNextSOF(FdoExtension->MiniPortExt);
1401 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1402 break;
1403 }
1404 }
1405
1406 ULONG
1407 NTAPI
1408 USBPORT_DmaEndpointPaused(IN PDEVICE_OBJECT FdoDevice,
1409 IN PUSBPORT_ENDPOINT Endpoint)
1410 {
1411 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1412 PUSBPORT_REGISTRATION_PACKET Packet;
1413 PLIST_ENTRY Entry;
1414 PUSBPORT_TRANSFER Transfer;
1415 PURB Urb;
1416 ULONG Frame;
1417 ULONG CurrentFrame;
1418 ULONG CompletedLen = 0;
1419 KIRQL OldIrql;
1420
1421 DPRINT_CORE("USBPORT_DmaEndpointPaused \n");
1422
1423 FdoExtension = FdoDevice->DeviceExtension;
1424 Packet = &FdoExtension->MiniPortInterface->Packet;
1425
1426 Entry = Endpoint->TransferList.Flink;
1427
1428 if (Entry == &Endpoint->TransferList)
1429 return USBPORT_ENDPOINT_ACTIVE;
1430
1431 while (Entry && Entry != &Endpoint->TransferList)
1432 {
1433 Transfer = CONTAINING_RECORD(Entry,
1434 USBPORT_TRANSFER,
1435 TransferLink);
1436
1437 if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED))
1438 {
1439 if (Transfer->Flags & TRANSFER_FLAG_ISO &&
1440 Transfer->Flags & TRANSFER_FLAG_SUBMITED &&
1441 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1442 {
1443 Urb = Transfer->Urb;
1444
1445 Frame = Urb->UrbIsochronousTransfer.StartFrame +
1446 Urb->UrbIsochronousTransfer.NumberOfPackets;
1447
1448 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1449 CurrentFrame = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt);
1450 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1451
1452 if (Frame + 1 > CurrentFrame)
1453 {
1454 return USBPORT_GetEndpointState(Endpoint);
1455 }
1456 }
1457
1458 if ((Transfer->Flags & TRANSFER_FLAG_SUBMITED) &&
1459 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1460 {
1461 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1462
1463 Packet->AbortTransfer(FdoExtension->MiniPortExt,
1464 Endpoint + 1,
1465 Transfer->MiniportTransfer,
1466 &CompletedLen);
1467
1468 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1469
1470 if (Transfer->Flags & TRANSFER_FLAG_ISO)
1471 {
1472 DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_FlushIsoTransfer\n");
1473 ASSERT(FALSE); //USBPORT_FlushIsoTransfer();
1474 }
1475 else
1476 {
1477 Transfer->CompletedTransferLen = CompletedLen;
1478 }
1479 }
1480
1481 RemoveEntryList(&Transfer->TransferLink);
1482 Entry = Transfer->TransferLink.Flink;
1483
1484 if (Transfer->Flags & TRANSFER_FLAG_SPLITED)
1485 {
1486 USBPORT_CancelSplitTransfer(Transfer);
1487 }
1488 else
1489 {
1490 InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink);
1491 }
1492 }
1493 else
1494 {
1495 Entry = Transfer->TransferLink.Flink;
1496 }
1497 }
1498
1499 return USBPORT_ENDPOINT_ACTIVE;
1500 }
1501
1502 ULONG
1503 NTAPI
1504 USBPORT_DmaEndpointActive(IN PDEVICE_OBJECT FdoDevice,
1505 IN PUSBPORT_ENDPOINT Endpoint)
1506 {
1507 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1508 PUSBPORT_REGISTRATION_PACKET Packet;
1509 PLIST_ENTRY Entry;
1510 PUSBPORT_TRANSFER Transfer;
1511 LARGE_INTEGER TimeOut;
1512 MPSTATUS MpStatus;
1513 KIRQL OldIrql;
1514
1515 DPRINT_CORE("USBPORT_DmaEndpointActive \n");
1516
1517 FdoExtension = FdoDevice->DeviceExtension;
1518
1519 Entry = Endpoint->TransferList.Flink;
1520
1521 while (Entry && Entry != &Endpoint->TransferList)
1522 {
1523 Transfer = CONTAINING_RECORD(Entry,
1524 USBPORT_TRANSFER,
1525 TransferLink);
1526
1527 if (!(Transfer->Flags & TRANSFER_FLAG_SUBMITED) &&
1528 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1529 {
1530 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1531
1532 Packet = &FdoExtension->MiniPortInterface->Packet;
1533
1534 if (Transfer->Flags & TRANSFER_FLAG_ISO)
1535 {
1536 DPRINT1("USBPORT_DmaEndpointActive: FIXME call SubmitIsoTransfer\n");
1537
1538 MpStatus = Packet->SubmitIsoTransfer(FdoExtension->MiniPortExt,
1539 Endpoint + 1,
1540 &Transfer->TransferParameters,
1541 Transfer->MiniportTransfer,
1542 NULL);//&Transfer->IsoTransferParameters);
1543 }
1544 else
1545 {
1546 MpStatus = Packet->SubmitTransfer(FdoExtension->MiniPortExt,
1547 Endpoint + 1,
1548 &Transfer->TransferParameters,
1549 Transfer->MiniportTransfer,
1550 &Transfer->SgList);
1551 }
1552
1553 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1554
1555 if (MpStatus)
1556 {
1557 if ((MpStatus != MP_STATUS_FAILURE) && Transfer->Flags & TRANSFER_FLAG_ISO)
1558 {
1559 DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_ErrorCompleteIsoTransfer\n");
1560 ASSERT(FALSE); //USBPORT_ErrorCompleteIsoTransfer();
1561 }
1562
1563 return USBPORT_ENDPOINT_ACTIVE;
1564 }
1565
1566 Transfer->Flags |= TRANSFER_FLAG_SUBMITED;
1567 KeQuerySystemTime(&Transfer->Time);
1568
1569 TimeOut.QuadPart = 10000 * Transfer->TimeOut;
1570 Transfer->Time.QuadPart += TimeOut.QuadPart;
1571 }
1572
1573 if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED))
1574 {
1575 return USBPORT_ENDPOINT_PAUSED;
1576 }
1577
1578 Entry = Transfer->TransferLink.Flink;
1579 }
1580
1581 return USBPORT_ENDPOINT_ACTIVE;
1582 }
1583
1584 VOID
1585 NTAPI
1586 USBPORT_DmaEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint)
1587 {
1588 PDEVICE_OBJECT FdoDevice;
1589 ULONG PrevState;
1590 ULONG EndpointState;
1591 BOOLEAN IsPaused = FALSE;
1592
1593 DPRINT_CORE("USBPORT_DmaEndpointWorker ... \n");
1594
1595 FdoDevice = Endpoint->FdoDevice;
1596
1597 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1598
1599 PrevState = USBPORT_GetEndpointState(Endpoint);
1600
1601 if (PrevState == USBPORT_ENDPOINT_PAUSED)
1602 {
1603 EndpointState = USBPORT_DmaEndpointPaused(FdoDevice, Endpoint);
1604 }
1605 else if (PrevState == USBPORT_ENDPOINT_ACTIVE)
1606 {
1607 EndpointState = USBPORT_DmaEndpointActive(FdoDevice, Endpoint);
1608 }
1609 else
1610 {
1611 #ifndef NDEBUG_USBPORT_CORE
1612 DPRINT1("USBPORT_DmaEndpointWorker: DbgBreakPoint. EndpointState - %x\n",
1613 EndpointState);
1614 DbgBreakPoint();
1615 #endif
1616 EndpointState = USBPORT_ENDPOINT_UNKNOWN;
1617 }
1618
1619 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1620
1621 USBPORT_FlushCancelList(Endpoint);
1622
1623 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1624
1625 if (EndpointState == PrevState)
1626 {
1627 if (EndpointState == USBPORT_ENDPOINT_PAUSED)
1628 {
1629 IsPaused = TRUE;
1630 }
1631 }
1632 else
1633 {
1634 USBPORT_SetEndpointState(Endpoint, EndpointState);
1635 }
1636
1637 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1638
1639 if (IsPaused)
1640 {
1641 USBPORT_InvalidateEndpointHandler(FdoDevice,
1642 Endpoint,
1643 INVALIDATE_ENDPOINT_WORKER_THREAD);
1644 }
1645
1646 DPRINT_CORE("USBPORT_DmaEndpointWorker exit \n");
1647 }
1648
1649 BOOLEAN
1650 NTAPI
1651 USBPORT_EndpointWorker(IN PUSBPORT_ENDPOINT Endpoint,
1652 IN BOOLEAN LockNotChecked)
1653 {
1654 PDEVICE_OBJECT FdoDevice;
1655 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1656 PUSBPORT_REGISTRATION_PACKET Packet;
1657 ULONG EndpointState;
1658
1659 DPRINT_CORE("USBPORT_EndpointWorker: Endpoint - %p, LockNotChecked - %x\n",
1660 Endpoint,
1661 LockNotChecked);
1662
1663 FdoDevice = Endpoint->FdoDevice;
1664 FdoExtension = FdoDevice->DeviceExtension;
1665 Packet = &FdoExtension->MiniPortInterface->Packet;
1666
1667 if (LockNotChecked == FALSE)
1668 {
1669 if (InterlockedIncrement(&Endpoint->LockCounter))
1670 {
1671 InterlockedDecrement(&Endpoint->LockCounter);
1672 DPRINT_CORE("USBPORT_EndpointWorker: LockCounter > 0\n");
1673 return TRUE;
1674 }
1675 }
1676
1677 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1678
1679 KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock);
1680
1681 if (USBPORT_GetEndpointState(Endpoint) == USBPORT_ENDPOINT_CLOSED)
1682 {
1683 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1684 InterlockedDecrement(&Endpoint->LockCounter);
1685 DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_CLOSED. return FALSE\n");
1686 return FALSE;
1687 }
1688
1689 if ((Endpoint->Flags & (ENDPOINT_FLAG_ROOTHUB_EP0 | ENDPOINT_FLAG_NUKE)) == 0)
1690 {
1691 KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1692 Packet->PollEndpoint(FdoExtension->MiniPortExt, Endpoint + 1);
1693 KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1694 }
1695
1696 EndpointState = USBPORT_GetEndpointState(Endpoint);
1697
1698 if (EndpointState == USBPORT_ENDPOINT_REMOVE)
1699 {
1700 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1701 Endpoint->StateLast = USBPORT_ENDPOINT_CLOSED;
1702 Endpoint->StateNext = USBPORT_ENDPOINT_CLOSED;
1703 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1704
1705 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1706
1707 KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
1708
1709 ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
1710 &Endpoint->CloseLink,
1711 &FdoExtension->EndpointClosedSpinLock);
1712
1713 KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
1714
1715 InterlockedDecrement(&Endpoint->LockCounter);
1716 DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_REMOVE. return FALSE\n");
1717 return FALSE;
1718 }
1719
1720 if (!IsListEmpty(&Endpoint->PendingTransferList) ||
1721 !IsListEmpty(&Endpoint->TransferList) ||
1722 !IsListEmpty(&Endpoint->CancelList))
1723 {
1724 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1725
1726 EndpointState = USBPORT_GetEndpointState(Endpoint);
1727
1728 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1729 if (EndpointState == Endpoint->StateNext)
1730 {
1731 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1732
1733 if (Endpoint->EndpointWorker)
1734 {
1735 USBPORT_DmaEndpointWorker(Endpoint);
1736 }
1737 else
1738 {
1739 USBPORT_RootHubEndpointWorker(Endpoint);
1740 }
1741
1742 USBPORT_FlushAbortList(Endpoint);
1743
1744 InterlockedDecrement(&Endpoint->LockCounter);
1745 DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n");
1746 return FALSE;
1747 }
1748
1749 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1750 InterlockedDecrement(&Endpoint->LockCounter);
1751
1752 DPRINT_CORE("USBPORT_EndpointWorker: return TRUE\n");
1753 return TRUE;
1754 }
1755
1756 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1757
1758 USBPORT_FlushAbortList(Endpoint);
1759
1760 InterlockedDecrement(&Endpoint->LockCounter);
1761 DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n");
1762 return FALSE;
1763 }