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