xref: /reactos/drivers/usb/usbport/endpoint.c (revision f2df3bf0)
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(&FdoExtension->MiniportSpinLock, &MiniportOldIrql);
1190 
1191     Packet->SetEndpointState(FdoExtension->MiniPortExt,
1192                              Endpoint + 1,
1193                              USBPORT_ENDPOINT_REMOVE);
1194 
1195     KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql);
1196 
1197     USBPORT_Wait(FdoDevice, 2);
1198 
1199     MiniportCloseEndpoint(FdoDevice, Endpoint);
1200 
1201     RtlZeroMemory(Endpoint + 1,
1202                   Packet->MiniPortEndpointSize);
1203 
1204     if (Endpoint->HeaderBuffer)
1205     {
1206         USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer);
1207         Endpoint->HeaderBuffer = NULL;
1208     }
1209 
1210     KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql);
1211 
1212     Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
1213                                       &Endpoint->EndpointProperties,
1214                                       &EndpointRequirements);
1215 
1216     KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql);
1217 
1218     if (EndpointRequirements.HeaderBufferSize)
1219     {
1220         HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice,
1221                                                     EndpointRequirements.HeaderBufferSize);
1222     }
1223     else
1224     {
1225         HeaderBuffer = NULL;
1226     }
1227 
1228     if (HeaderBuffer || EndpointRequirements.HeaderBufferSize == 0)
1229     {
1230         Endpoint->HeaderBuffer = HeaderBuffer;
1231         Status = STATUS_SUCCESS;
1232     }
1233     else
1234     {
1235         Endpoint->HeaderBuffer = 0;
1236         Status = STATUS_INSUFFICIENT_RESOURCES;
1237     }
1238 
1239     if (Endpoint->HeaderBuffer && HeaderBuffer)
1240     {
1241         Endpoint->EndpointProperties.BufferVA = HeaderBuffer->VirtualAddress;
1242         Endpoint->EndpointProperties.BufferPA = HeaderBuffer->PhysicalAddress;
1243         Endpoint->EndpointProperties.BufferLength = HeaderBuffer->BufferLength;
1244     }
1245 
1246     if (NT_SUCCESS(Status))
1247     {
1248         MiniportOpenEndpoint(FdoDevice, Endpoint);
1249 
1250         KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1251         KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1252 
1253         if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE)
1254         {
1255             KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1256 
1257             Packet->SetEndpointState(FdoExtension->MiniPortExt,
1258                                      Endpoint + 1,
1259                                      USBPORT_ENDPOINT_ACTIVE);
1260 
1261             KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1262         }
1263 
1264         KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1265         KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1266     }
1267 
1268     InterlockedDecrement(&Endpoint->LockCounter);
1269 
1270     return Status;
1271 }
1272 
1273 VOID
1274 NTAPI
1275 USBPORT_FlushClosedEndpointList(IN PDEVICE_OBJECT FdoDevice)
1276 {
1277     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
1278     KIRQL OldIrql;
1279     PLIST_ENTRY ClosedList;
1280     PUSBPORT_ENDPOINT Endpoint;
1281 
1282     DPRINT_CORE("USBPORT_FlushClosedEndpointList: ... \n");
1283 
1284     FdoExtension = FdoDevice->DeviceExtension;
1285 
1286     KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql);
1287     ClosedList = &FdoExtension->EndpointClosedList;
1288 
1289     while (!IsListEmpty(ClosedList))
1290     {
1291         Endpoint = CONTAINING_RECORD(ClosedList->Flink,
1292                                      USBPORT_ENDPOINT,
1293                                      CloseLink);
1294 
1295         RemoveHeadList(ClosedList);
1296         Endpoint->CloseLink.Flink = NULL;
1297         Endpoint->CloseLink.Blink = NULL;
1298 
1299         KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql);
1300 
1301         USBPORT_DeleteEndpoint(FdoDevice, Endpoint);
1302 
1303         KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql);
1304     }
1305 
1306     KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql);
1307 }
1308 
1309 VOID
1310 NTAPI
1311 USBPORT_InvalidateEndpointHandler(IN PDEVICE_OBJECT FdoDevice,
1312                                   IN PUSBPORT_ENDPOINT Endpoint,
1313                                   IN ULONG Type)
1314 {
1315     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1316     PUSBPORT_REGISTRATION_PACKET Packet;
1317     PLIST_ENTRY Entry;
1318     PLIST_ENTRY WorkerLink;
1319     PUSBPORT_ENDPOINT endpoint;
1320     KIRQL OldIrql;
1321     BOOLEAN IsAddEntry = FALSE;
1322 
1323     DPRINT_CORE("USBPORT_InvalidateEndpointHandler: Endpoint - %p, Type - %x\n",
1324                 Endpoint,
1325                 Type);
1326 
1327     FdoExtension = FdoDevice->DeviceExtension;
1328     Packet = &FdoExtension->MiniPortInterface->Packet;
1329 
1330     if (Endpoint)
1331     {
1332         WorkerLink = &Endpoint->WorkerLink;
1333         KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
1334         DPRINT_CORE("USBPORT_InvalidateEndpointHandler: KeAcquireSpinLock \n");
1335 
1336         if ((!WorkerLink->Flink || !WorkerLink->Blink) &&
1337             !(Endpoint->Flags & ENDPOINT_FLAG_IDLE) &&
1338             USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_CLOSED)
1339         {
1340             DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n");
1341             InsertTailList(&FdoExtension->WorkerList, WorkerLink);
1342             IsAddEntry = TRUE;
1343         }
1344 
1345         KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
1346 
1347         if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
1348             Type = INVALIDATE_ENDPOINT_WORKER_THREAD;
1349     }
1350     else
1351     {
1352         KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
1353 
1354         Entry = &FdoExtension->EndpointList;
1355 
1356         while (Entry && Entry != &FdoExtension->EndpointList)
1357         {
1358             endpoint = CONTAINING_RECORD(Entry,
1359                                          USBPORT_ENDPOINT,
1360                                          EndpointLink);
1361 
1362             if (!endpoint->WorkerLink.Flink || !endpoint->WorkerLink.Blink)
1363             {
1364                 if (!(endpoint->Flags & ENDPOINT_FLAG_IDLE) &&
1365                     !(endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) &&
1366                     USBPORT_GetEndpointState(endpoint) != USBPORT_ENDPOINT_CLOSED)
1367                 {
1368                     DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n");
1369                     InsertTailList(&FdoExtension->WorkerList, &endpoint->WorkerLink);
1370                     IsAddEntry = TRUE;
1371                 }
1372             }
1373 
1374             Entry = endpoint->EndpointLink.Flink;
1375         }
1376 
1377         KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
1378     }
1379 
1380     if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)
1381     {
1382         Type = INVALIDATE_ENDPOINT_WORKER_THREAD;
1383     }
1384     else if (IsAddEntry == FALSE && Type == INVALIDATE_ENDPOINT_INT_NEXT_SOF)
1385     {
1386         Type = INVALIDATE_ENDPOINT_ONLY;
1387     }
1388 
1389     switch (Type)
1390     {
1391         case INVALIDATE_ENDPOINT_WORKER_THREAD:
1392             USBPORT_SignalWorkerThread(FdoDevice);
1393             break;
1394 
1395         case INVALIDATE_ENDPOINT_WORKER_DPC:
1396             KeInsertQueueDpc(&FdoExtension->WorkerRequestDpc, NULL, NULL);
1397             break;
1398 
1399         case INVALIDATE_ENDPOINT_INT_NEXT_SOF:
1400             KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1401             Packet->InterruptNextSOF(FdoExtension->MiniPortExt);
1402             KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1403             break;
1404     }
1405 }
1406 
1407 ULONG
1408 NTAPI
1409 USBPORT_DmaEndpointPaused(IN PDEVICE_OBJECT FdoDevice,
1410                           IN PUSBPORT_ENDPOINT Endpoint)
1411 {
1412     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1413     PUSBPORT_REGISTRATION_PACKET Packet;
1414     PLIST_ENTRY Entry;
1415     PUSBPORT_TRANSFER Transfer;
1416     PURB Urb;
1417     ULONG Frame;
1418     ULONG CurrentFrame;
1419     ULONG CompletedLen = 0;
1420     KIRQL OldIrql;
1421 
1422     DPRINT_CORE("USBPORT_DmaEndpointPaused \n");
1423 
1424     FdoExtension = FdoDevice->DeviceExtension;
1425     Packet = &FdoExtension->MiniPortInterface->Packet;
1426 
1427     Entry = Endpoint->TransferList.Flink;
1428 
1429     if (Entry == &Endpoint->TransferList)
1430         return USBPORT_ENDPOINT_ACTIVE;
1431 
1432     while (Entry && Entry != &Endpoint->TransferList)
1433     {
1434         Transfer = CONTAINING_RECORD(Entry,
1435                                      USBPORT_TRANSFER,
1436                                      TransferLink);
1437 
1438         if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED))
1439         {
1440             if (Transfer->Flags & TRANSFER_FLAG_ISO &&
1441                 Transfer->Flags & TRANSFER_FLAG_SUBMITED &&
1442                 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1443             {
1444                 Urb = Transfer->Urb;
1445 
1446                 Frame = Urb->UrbIsochronousTransfer.StartFrame +
1447                         Urb->UrbIsochronousTransfer.NumberOfPackets;
1448 
1449                 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1450                 CurrentFrame = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt);
1451                 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1452 
1453                 if (Frame + 1 > CurrentFrame)
1454                 {
1455                     return USBPORT_GetEndpointState(Endpoint);
1456                 }
1457             }
1458 
1459             if ((Transfer->Flags & TRANSFER_FLAG_SUBMITED) &&
1460                  !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1461             {
1462                 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1463 
1464                 Packet->AbortTransfer(FdoExtension->MiniPortExt,
1465                                       Endpoint + 1,
1466                                       Transfer->MiniportTransfer,
1467                                       &CompletedLen);
1468 
1469                 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1470 
1471                 if (Transfer->Flags & TRANSFER_FLAG_ISO)
1472                 {
1473                     DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_FlushIsoTransfer\n");
1474                     ASSERT(FALSE); //USBPORT_FlushIsoTransfer();
1475                 }
1476                 else
1477                 {
1478                     Transfer->CompletedTransferLen = CompletedLen;
1479                 }
1480             }
1481 
1482             RemoveEntryList(&Transfer->TransferLink);
1483             Entry = Transfer->TransferLink.Flink;
1484 
1485             if (Transfer->Flags & TRANSFER_FLAG_SPLITED)
1486             {
1487                 USBPORT_CancelSplitTransfer(Transfer);
1488             }
1489             else
1490             {
1491                 InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink);
1492             }
1493         }
1494         else
1495         {
1496             Entry = Transfer->TransferLink.Flink;
1497         }
1498     }
1499 
1500     return USBPORT_ENDPOINT_ACTIVE;
1501 }
1502 
1503 ULONG
1504 NTAPI
1505 USBPORT_DmaEndpointActive(IN PDEVICE_OBJECT FdoDevice,
1506                           IN PUSBPORT_ENDPOINT Endpoint)
1507 {
1508     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1509     PUSBPORT_REGISTRATION_PACKET Packet;
1510     PLIST_ENTRY Entry;
1511     PUSBPORT_TRANSFER Transfer;
1512     LARGE_INTEGER TimeOut;
1513     MPSTATUS MpStatus;
1514     KIRQL OldIrql;
1515 
1516     DPRINT_CORE("USBPORT_DmaEndpointActive \n");
1517 
1518     FdoExtension = FdoDevice->DeviceExtension;
1519 
1520     Entry = Endpoint->TransferList.Flink;
1521 
1522     while (Entry && Entry != &Endpoint->TransferList)
1523     {
1524         Transfer = CONTAINING_RECORD(Entry,
1525                                      USBPORT_TRANSFER,
1526                                      TransferLink);
1527 
1528         if (!(Transfer->Flags & TRANSFER_FLAG_SUBMITED) &&
1529              !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1530         {
1531             KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1532 
1533             Packet = &FdoExtension->MiniPortInterface->Packet;
1534 
1535             if (Transfer->Flags & TRANSFER_FLAG_ISO)
1536             {
1537                 DPRINT1("USBPORT_DmaEndpointActive: FIXME call SubmitIsoTransfer\n");
1538 
1539                 MpStatus = Packet->SubmitIsoTransfer(FdoExtension->MiniPortExt,
1540                                                      Endpoint + 1,
1541                                                      &Transfer->TransferParameters,
1542                                                      Transfer->MiniportTransfer,
1543                                                      NULL);//&Transfer->IsoTransferParameters);
1544             }
1545             else
1546             {
1547                 MpStatus = Packet->SubmitTransfer(FdoExtension->MiniPortExt,
1548                                                   Endpoint + 1,
1549                                                   &Transfer->TransferParameters,
1550                                                   Transfer->MiniportTransfer,
1551                                                   &Transfer->SgList);
1552             }
1553 
1554             KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1555 
1556             if (MpStatus)
1557             {
1558                 if ((MpStatus != MP_STATUS_FAILURE) && Transfer->Flags & TRANSFER_FLAG_ISO)
1559                 {
1560                     DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_ErrorCompleteIsoTransfer\n");
1561                     ASSERT(FALSE); //USBPORT_ErrorCompleteIsoTransfer();
1562                 }
1563 
1564                 return USBPORT_ENDPOINT_ACTIVE;
1565             }
1566 
1567             Transfer->Flags |= TRANSFER_FLAG_SUBMITED;
1568             KeQuerySystemTime(&Transfer->Time);
1569 
1570             TimeOut.QuadPart = 10000 * Transfer->TimeOut;
1571             Transfer->Time.QuadPart += TimeOut.QuadPart;
1572         }
1573 
1574         if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED))
1575         {
1576             return USBPORT_ENDPOINT_PAUSED;
1577         }
1578 
1579         Entry = Transfer->TransferLink.Flink;
1580     }
1581 
1582     return USBPORT_ENDPOINT_ACTIVE;
1583 }
1584 
1585 VOID
1586 NTAPI
1587 USBPORT_DmaEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint)
1588 {
1589     PDEVICE_OBJECT FdoDevice;
1590     ULONG PrevState;
1591     ULONG EndpointState;
1592     BOOLEAN IsPaused = FALSE;
1593 
1594     DPRINT_CORE("USBPORT_DmaEndpointWorker ... \n");
1595 
1596     FdoDevice = Endpoint->FdoDevice;
1597 
1598     KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1599 
1600     PrevState = USBPORT_GetEndpointState(Endpoint);
1601 
1602     if (PrevState == USBPORT_ENDPOINT_PAUSED)
1603     {
1604         EndpointState = USBPORT_DmaEndpointPaused(FdoDevice, Endpoint);
1605     }
1606     else if (PrevState == USBPORT_ENDPOINT_ACTIVE)
1607     {
1608         EndpointState = USBPORT_DmaEndpointActive(FdoDevice, Endpoint);
1609     }
1610     else
1611     {
1612 #ifndef NDEBUG_USBPORT_CORE
1613         DPRINT1("USBPORT_DmaEndpointWorker: DbgBreakPoint. EndpointState - %x\n",
1614                 EndpointState);
1615         DbgBreakPoint();
1616 #endif
1617         EndpointState = USBPORT_ENDPOINT_UNKNOWN;
1618     }
1619 
1620     KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1621 
1622     USBPORT_FlushCancelList(Endpoint);
1623 
1624     KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1625 
1626     if (EndpointState == PrevState)
1627     {
1628         if (EndpointState == USBPORT_ENDPOINT_PAUSED)
1629         {
1630             IsPaused = TRUE;
1631         }
1632     }
1633     else
1634     {
1635         USBPORT_SetEndpointState(Endpoint, EndpointState);
1636     }
1637 
1638     KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1639 
1640     if (IsPaused)
1641     {
1642        USBPORT_InvalidateEndpointHandler(FdoDevice,
1643                                          Endpoint,
1644                                          INVALIDATE_ENDPOINT_WORKER_THREAD);
1645     }
1646 
1647     DPRINT_CORE("USBPORT_DmaEndpointWorker exit \n");
1648 }
1649 
1650 BOOLEAN
1651 NTAPI
1652 USBPORT_EndpointWorker(IN PUSBPORT_ENDPOINT Endpoint,
1653                        IN BOOLEAN LockNotChecked)
1654 {
1655     PDEVICE_OBJECT FdoDevice;
1656     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1657     PUSBPORT_REGISTRATION_PACKET Packet;
1658     ULONG EndpointState;
1659 
1660     DPRINT_CORE("USBPORT_EndpointWorker: Endpoint - %p, LockNotChecked - %x\n",
1661            Endpoint,
1662            LockNotChecked);
1663 
1664     FdoDevice = Endpoint->FdoDevice;
1665     FdoExtension = FdoDevice->DeviceExtension;
1666     Packet = &FdoExtension->MiniPortInterface->Packet;
1667 
1668     if (LockNotChecked == FALSE)
1669     {
1670         if (InterlockedIncrement(&Endpoint->LockCounter))
1671         {
1672             InterlockedDecrement(&Endpoint->LockCounter);
1673             DPRINT_CORE("USBPORT_EndpointWorker: LockCounter > 0\n");
1674             return TRUE;
1675         }
1676     }
1677 
1678     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1679 
1680     KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock);
1681 
1682     if (USBPORT_GetEndpointState(Endpoint) == USBPORT_ENDPOINT_CLOSED)
1683     {
1684         KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1685         InterlockedDecrement(&Endpoint->LockCounter);
1686         DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_CLOSED. return FALSE\n");
1687         return FALSE;
1688     }
1689 
1690     if ((Endpoint->Flags & (ENDPOINT_FLAG_ROOTHUB_EP0 | ENDPOINT_FLAG_NUKE)) == 0)
1691     {
1692         KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1693         Packet->PollEndpoint(FdoExtension->MiniPortExt, Endpoint + 1);
1694         KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1695     }
1696 
1697     EndpointState = USBPORT_GetEndpointState(Endpoint);
1698 
1699     if (EndpointState == USBPORT_ENDPOINT_REMOVE)
1700     {
1701         KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1702         Endpoint->StateLast = USBPORT_ENDPOINT_CLOSED;
1703         Endpoint->StateNext = USBPORT_ENDPOINT_CLOSED;
1704         KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1705 
1706         KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1707 
1708         KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
1709 
1710         ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
1711                                     &Endpoint->CloseLink,
1712                                     &FdoExtension->EndpointClosedSpinLock);
1713 
1714         KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
1715 
1716         InterlockedDecrement(&Endpoint->LockCounter);
1717         DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_REMOVE. return FALSE\n");
1718         return FALSE;
1719     }
1720 
1721     if (!IsListEmpty(&Endpoint->PendingTransferList) ||
1722         !IsListEmpty(&Endpoint->TransferList) ||
1723         !IsListEmpty(&Endpoint->CancelList))
1724     {
1725         KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1726 
1727         EndpointState = USBPORT_GetEndpointState(Endpoint);
1728 
1729         KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1730         if (EndpointState == Endpoint->StateNext)
1731         {
1732             KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1733 
1734             if (Endpoint->EndpointWorker)
1735             {
1736                 USBPORT_DmaEndpointWorker(Endpoint);
1737             }
1738             else
1739             {
1740                 USBPORT_RootHubEndpointWorker(Endpoint);
1741             }
1742 
1743             USBPORT_FlushAbortList(Endpoint);
1744 
1745             InterlockedDecrement(&Endpoint->LockCounter);
1746             DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n");
1747             return FALSE;
1748         }
1749 
1750         KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1751         InterlockedDecrement(&Endpoint->LockCounter);
1752 
1753         DPRINT_CORE("USBPORT_EndpointWorker: return TRUE\n");
1754         return TRUE;
1755     }
1756 
1757     KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1758 
1759     USBPORT_FlushAbortList(Endpoint);
1760 
1761     InterlockedDecrement(&Endpoint->LockCounter);
1762     DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n");
1763     return FALSE;
1764 }
1765