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