xref: /reactos/drivers/usb/usbport/usbport.c (revision 84344399)
1 /*
2  * PROJECT:     ReactOS USB Port Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBPort main driver 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 #define NDEBUG_USBPORT_INTERRUPT
15 #define NDEBUG_USBPORT_TIMER
16 #include "usbdebug.h"
17 
18 LIST_ENTRY USBPORT_MiniPortDrivers = {NULL, NULL};
19 LIST_ENTRY USBPORT_USB1FdoList = {NULL, NULL};
20 LIST_ENTRY USBPORT_USB2FdoList = {NULL, NULL};
21 
22 KSPIN_LOCK USBPORT_SpinLock;
23 BOOLEAN USBPORT_Initialized = FALSE;
24 
25 PDEVICE_OBJECT
26 NTAPI
27 USBPORT_FindUSB2Controller(IN PDEVICE_OBJECT FdoDevice)
28 {
29     PUSBPORT_DEVICE_EXTENSION FdoExtension;
30     PUSBPORT_DEVICE_EXTENSION USB2FdoExtension;
31     KIRQL OldIrql;
32     PLIST_ENTRY USB2FdoEntry;
33     PDEVICE_OBJECT USB2FdoDevice = NULL;
34 
35     DPRINT("USBPORT_FindUSB2Controller: FdoDevice - %p\n", FdoDevice);
36 
37     FdoExtension = FdoDevice->DeviceExtension;
38 
39     KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql);
40 
41     USB2FdoEntry = USBPORT_USB2FdoList.Flink;
42 
43     while (USB2FdoEntry && USB2FdoEntry != &USBPORT_USB2FdoList)
44     {
45         USB2FdoExtension = CONTAINING_RECORD(USB2FdoEntry,
46                                              USBPORT_DEVICE_EXTENSION,
47                                              ControllerLink);
48 
49         if (USB2FdoExtension->BusNumber == FdoExtension->BusNumber &&
50             USB2FdoExtension->PciDeviceNumber == FdoExtension->PciDeviceNumber)
51         {
52             USB2FdoDevice = USB2FdoExtension->CommonExtension.SelfDevice;
53             break;
54         }
55 
56         USB2FdoEntry = USB2FdoEntry->Flink;
57     }
58 
59     KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql);
60 
61     return USB2FdoDevice;
62 }
63 
64 VOID
65 NTAPI
66 USBPORT_AddUSB1Fdo(IN PDEVICE_OBJECT FdoDevice)
67 {
68     PUSBPORT_DEVICE_EXTENSION FdoExtension;
69 
70     DPRINT("USBPORT_AddUSB1Fdo: FdoDevice - %p\n", FdoDevice);
71 
72     FdoExtension = FdoDevice->DeviceExtension;
73     FdoExtension->Flags |= USBPORT_FLAG_REGISTERED_FDO;
74 
75     ExInterlockedInsertTailList(&USBPORT_USB1FdoList,
76                                 &FdoExtension->ControllerLink,
77                                 &USBPORT_SpinLock);
78 }
79 
80 VOID
81 NTAPI
82 USBPORT_AddUSB2Fdo(IN PDEVICE_OBJECT FdoDevice)
83 {
84     PUSBPORT_DEVICE_EXTENSION FdoExtension;
85 
86     DPRINT("USBPORT_AddUSB2Fdo: FdoDevice - %p\n", FdoDevice);
87 
88     FdoExtension = FdoDevice->DeviceExtension;
89     FdoExtension->Flags |= USBPORT_FLAG_REGISTERED_FDO;
90 
91     ExInterlockedInsertTailList(&USBPORT_USB2FdoList,
92                                 &FdoExtension->ControllerLink,
93                                 &USBPORT_SpinLock);
94 }
95 
96 VOID
97 NTAPI
98 USBPORT_RemoveUSBxFdo(IN PDEVICE_OBJECT FdoDevice)
99 {
100     PUSBPORT_DEVICE_EXTENSION FdoExtension;
101     KIRQL OldIrql;
102 
103     DPRINT("USBPORT_RemoveUSBxFdo: FdoDevice - %p\n", FdoDevice);
104 
105     FdoExtension = FdoDevice->DeviceExtension;
106 
107     KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql);
108     RemoveEntryList(&FdoExtension->ControllerLink);
109     KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql);
110 
111     FdoExtension->Flags &= ~USBPORT_FLAG_REGISTERED_FDO;
112 
113     FdoExtension->ControllerLink.Flink = NULL;
114     FdoExtension->ControllerLink.Blink = NULL;
115 }
116 
117 BOOLEAN
118 NTAPI
119 USBPORT_IsCompanionFdoExtension(IN PDEVICE_OBJECT USB2FdoDevice,
120                                 IN PUSBPORT_DEVICE_EXTENSION USB1FdoExtension)
121 {
122     PUSBPORT_DEVICE_EXTENSION USB2FdoExtension;
123 
124     DPRINT("USBPORT_IsCompanionFdoExtension: USB2Fdo - %p, USB1FdoExtension - %p\n",
125            USB2FdoDevice,
126            USB1FdoExtension);
127 
128     USB2FdoExtension = USB2FdoDevice->DeviceExtension;
129 
130     return USB2FdoExtension->BusNumber == USB1FdoExtension->BusNumber &&
131            USB2FdoExtension->PciDeviceNumber == USB1FdoExtension->PciDeviceNumber;
132 }
133 
134 PDEVICE_RELATIONS
135 NTAPI
136 USBPORT_FindCompanionControllers(IN PDEVICE_OBJECT USB2FdoDevice,
137                                  IN BOOLEAN IsObRefer,
138                                  IN BOOLEAN IsFDOsReturned)
139 {
140     PLIST_ENTRY USB1FdoList;
141     PUSBPORT_DEVICE_EXTENSION USB1FdoExtension;
142     ULONG NumControllers = 0;
143     PDEVICE_OBJECT * Entry;
144     PDEVICE_RELATIONS ControllersList = NULL;
145     KIRQL OldIrql;
146 
147     DPRINT("USBPORT_FindCompanionControllers: USB2Fdo - %p, IsObRefer - %x, IsFDOs - %x\n",
148            USB2FdoDevice,
149            IsObRefer,
150            IsFDOsReturned);
151 
152     KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql);
153 
154     USB1FdoList = USBPORT_USB1FdoList.Flink;
155 
156     while (USB1FdoList && USB1FdoList != &USBPORT_USB1FdoList)
157     {
158         USB1FdoExtension = CONTAINING_RECORD(USB1FdoList,
159                                              USBPORT_DEVICE_EXTENSION,
160                                              ControllerLink);
161 
162         if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC &&
163             USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension))
164         {
165             ++NumControllers;
166         }
167 
168         USB1FdoList = USB1FdoExtension->ControllerLink.Flink;
169     }
170 
171     DPRINT("USBPORT_FindCompanionControllers: NumControllers - %x\n",
172            NumControllers);
173 
174     if (!NumControllers)
175     {
176         goto Exit;
177     }
178 
179     ControllersList = ExAllocatePoolWithTag(NonPagedPool,
180                                             NumControllers * sizeof(DEVICE_RELATIONS),
181                                             USB_PORT_TAG);
182 
183     if (!ControllersList)
184     {
185         goto Exit;
186     }
187 
188     RtlZeroMemory(ControllersList, NumControllers * sizeof(DEVICE_RELATIONS));
189 
190     ControllersList->Count = NumControllers;
191 
192     USB1FdoList = USBPORT_USB1FdoList.Flink;
193 
194     Entry = &ControllersList->Objects[0];
195 
196     while (USB1FdoList && USB1FdoList != &USBPORT_USB1FdoList)
197     {
198         USB1FdoExtension = CONTAINING_RECORD(USB1FdoList,
199                                              USBPORT_DEVICE_EXTENSION,
200                                              ControllerLink);
201 
202         if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC &&
203             USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension))
204         {
205             *Entry = USB1FdoExtension->CommonExtension.LowerPdoDevice;
206 
207             if (IsObRefer)
208             {
209                 ObReferenceObject(USB1FdoExtension->CommonExtension.LowerPdoDevice);
210             }
211 
212             if (IsFDOsReturned)
213             {
214                 *Entry = USB1FdoExtension->CommonExtension.SelfDevice;
215             }
216 
217             ++Entry;
218         }
219 
220         USB1FdoList = USB1FdoExtension->ControllerLink.Flink;
221     }
222 
223 Exit:
224 
225     KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql);
226 
227     return ControllersList;
228 }
229 
230 MPSTATUS
231 NTAPI
232 USBPORT_NtStatusToMpStatus(NTSTATUS NtStatus)
233 {
234     DPRINT("USBPORT_NtStatusToMpStatus: NtStatus - %x\n", NtStatus);
235 
236     if (NtStatus == STATUS_SUCCESS)
237     {
238         return MP_STATUS_SUCCESS;
239     }
240     else
241     {
242         return MP_STATUS_UNSUCCESSFUL;
243     }
244 }
245 
246 NTSTATUS
247 NTAPI
248 USBPORT_SetRegistryKeyValue(IN PDEVICE_OBJECT DeviceObject,
249                             IN BOOL UseDriverKey,
250                             IN ULONG Type,
251                             IN PCWSTR ValueNameString,
252                             IN PVOID Data,
253                             IN ULONG DataSize)
254 {
255     UNICODE_STRING ValueName;
256     HANDLE KeyHandle;
257     NTSTATUS Status;
258 
259     DPRINT("USBPORT_SetRegistryKeyValue: ValueNameString - %S\n",
260            ValueNameString);
261 
262     if (UseDriverKey)
263     {
264         Status = IoOpenDeviceRegistryKey(DeviceObject,
265                                          PLUGPLAY_REGKEY_DRIVER,
266                                          STANDARD_RIGHTS_ALL,
267                                          &KeyHandle);
268     }
269     else
270     {
271         Status = IoOpenDeviceRegistryKey(DeviceObject,
272                                          PLUGPLAY_REGKEY_DEVICE,
273                                          STANDARD_RIGHTS_ALL,
274                                          &KeyHandle);
275     }
276 
277     if (NT_SUCCESS(Status))
278     {
279         RtlInitUnicodeString(&ValueName, ValueNameString);
280 
281         Status = ZwSetValueKey(KeyHandle,
282                                &ValueName,
283                                0,
284                                Type,
285                                Data,
286                                DataSize);
287 
288         ZwClose(KeyHandle);
289     }
290 
291     return Status;
292 }
293 
294 NTSTATUS
295 NTAPI
296 USBPORT_GetRegistryKeyValueFullInfo(IN PDEVICE_OBJECT FdoDevice,
297                                     IN PDEVICE_OBJECT PdoDevice,
298                                     IN BOOL UseDriverKey,
299                                     IN PCWSTR SourceString,
300                                     IN ULONG LengthStr,
301                                     IN PVOID Buffer,
302                                     IN ULONG BufferLength)
303 {
304     NTSTATUS Status;
305     PKEY_VALUE_FULL_INFORMATION KeyValue;
306     UNICODE_STRING ValueName;
307     HANDLE KeyHandle;
308     ULONG LengthKey;
309 
310     DPRINT("USBPORT_GetRegistryKeyValue: UseDriverKey - %x, SourceString - %S, LengthStr - %x, Buffer - %p, BufferLength - %x\n",
311            UseDriverKey,
312            SourceString,
313            LengthStr,
314            Buffer,
315            BufferLength);
316 
317     if (UseDriverKey)
318     {
319         Status = IoOpenDeviceRegistryKey(PdoDevice,
320                                          PLUGPLAY_REGKEY_DRIVER,
321                                          STANDARD_RIGHTS_ALL,
322                                          &KeyHandle);
323     }
324     else
325     {
326         Status = IoOpenDeviceRegistryKey(PdoDevice,
327                                          PLUGPLAY_REGKEY_DEVICE,
328                                          STANDARD_RIGHTS_ALL,
329                                          &KeyHandle);
330     }
331 
332     if (NT_SUCCESS(Status))
333     {
334         RtlInitUnicodeString(&ValueName, SourceString);
335 
336         LengthKey = sizeof(KEY_VALUE_FULL_INFORMATION) +
337                     LengthStr +
338                     BufferLength;
339 
340         KeyValue = ExAllocatePoolWithTag(PagedPool,
341                                          LengthKey,
342                                          USB_PORT_TAG);
343 
344         if (KeyValue)
345         {
346             RtlZeroMemory(KeyValue, LengthKey);
347 
348             Status = ZwQueryValueKey(KeyHandle,
349                                      &ValueName,
350                                      KeyValueFullInformation,
351                                      KeyValue,
352                                      LengthKey,
353                                      &LengthKey);
354 
355             if (NT_SUCCESS(Status))
356             {
357                 RtlCopyMemory(Buffer,
358                               (PUCHAR)KeyValue + KeyValue->DataOffset,
359                               BufferLength);
360             }
361 
362             ExFreePoolWithTag(KeyValue, USB_PORT_TAG);
363         }
364 
365         ZwClose(KeyHandle);
366     }
367 
368     return Status;
369 }
370 
371 MPSTATUS
372 NTAPI
373 USBPORT_GetMiniportRegistryKeyValue(IN PVOID MiniPortExtension,
374                                     IN BOOL UseDriverKey,
375                                     IN PCWSTR SourceString,
376                                     IN SIZE_T LengthStr,
377                                     IN PVOID Buffer,
378                                     IN SIZE_T BufferLength)
379 {
380     PUSBPORT_DEVICE_EXTENSION FdoExtension;
381     PDEVICE_OBJECT FdoDevice;
382     NTSTATUS Status;
383 
384     DPRINT("USBPORT_GetMiniportRegistryKeyValue: MiniPortExtension - %p, UseDriverKey - %x, SourceString - %S, LengthStr - %x, Buffer - %p, BufferLength - %x\n",
385            MiniPortExtension,
386            UseDriverKey,
387            SourceString,
388            LengthStr,
389            Buffer,
390            BufferLength);
391 
392     FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
393                                                sizeof(USBPORT_DEVICE_EXTENSION));
394 
395     FdoDevice = FdoExtension->CommonExtension.SelfDevice;
396 
397     Status = USBPORT_GetRegistryKeyValueFullInfo(FdoDevice,
398                                                  FdoExtension->CommonExtension.LowerPdoDevice,
399                                                  UseDriverKey,
400                                                  SourceString,
401                                                  LengthStr,
402                                                  Buffer,
403                                                  BufferLength);
404 
405     return USBPORT_NtStatusToMpStatus(Status);
406 }
407 
408 NTSTATUS
409 NTAPI
410 USBPORT_GetSetConfigSpaceData(IN PDEVICE_OBJECT FdoDevice,
411                               IN BOOLEAN IsReadData,
412                               IN PVOID Buffer,
413                               IN ULONG Offset,
414                               IN ULONG Length)
415 {
416     PUSBPORT_DEVICE_EXTENSION FdoExtension;
417     ULONG BytesReadWrite;
418 
419     DPRINT("USBPORT_GetSetConfigSpaceData ...\n");
420 
421     FdoExtension = FdoDevice->DeviceExtension;
422 
423     BytesReadWrite = Length;
424 
425     if (IsReadData)
426     {
427         RtlZeroMemory(Buffer, Length);
428 
429         BytesReadWrite = (*FdoExtension->BusInterface.GetBusData)
430                           (FdoExtension->BusInterface.Context,
431                            PCI_WHICHSPACE_CONFIG,
432                            Buffer,
433                            Offset,
434                            Length);
435     }
436     else
437     {
438         BytesReadWrite = (*FdoExtension->BusInterface.SetBusData)
439                           (FdoExtension->BusInterface.Context,
440                            PCI_WHICHSPACE_CONFIG,
441                            Buffer,
442                            Offset,
443                            Length);
444     }
445 
446     if (BytesReadWrite == Length)
447     {
448         return STATUS_SUCCESS;
449     }
450 
451     return STATUS_UNSUCCESSFUL;
452 }
453 
454 MPSTATUS
455 NTAPI
456 USBPORT_ReadWriteConfigSpace(IN PVOID MiniPortExtension,
457                              IN BOOLEAN IsReadData,
458                              IN PVOID Buffer,
459                              IN ULONG Offset,
460                              IN ULONG Length)
461 {
462     NTSTATUS Status;
463     PUSBPORT_DEVICE_EXTENSION FdoExtension;
464     PDEVICE_OBJECT FdoDevice;
465 
466     DPRINT("USBPORT_ReadWriteConfigSpace: ...\n");
467 
468     //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION));
469     FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
470                                                sizeof(USBPORT_DEVICE_EXTENSION));
471 
472     FdoDevice = FdoExtension->CommonExtension.SelfDevice;
473 
474     Status = USBPORT_GetSetConfigSpaceData(FdoDevice,
475                                            IsReadData,
476                                            Buffer,
477                                            Offset,
478                                            Length);
479 
480     return USBPORT_NtStatusToMpStatus(Status);
481 }
482 
483 NTSTATUS
484 NTAPI
485 USBPORT_USBDStatusToNtStatus(IN PURB Urb,
486                              IN USBD_STATUS USBDStatus)
487 {
488     NTSTATUS Status;
489 
490     if (USBD_ERROR(USBDStatus))
491     {
492         DPRINT1("USBPORT_USBDStatusToNtStatus: Urb - %p, USBDStatus - %x\n",
493                 Urb,
494                 USBDStatus);
495     }
496 
497     if (Urb)
498         Urb->UrbHeader.Status = USBDStatus;
499 
500     switch (USBDStatus)
501     {
502         case USBD_STATUS_SUCCESS:
503             Status = STATUS_SUCCESS;
504             break;
505 
506         case USBD_STATUS_INSUFFICIENT_RESOURCES:
507             Status = STATUS_INSUFFICIENT_RESOURCES;
508             break;
509 
510         case USBD_STATUS_DEVICE_GONE:
511             Status = STATUS_DEVICE_NOT_CONNECTED;
512             break;
513 
514         case USBD_STATUS_CANCELED:
515             Status = STATUS_CANCELLED;
516             break;
517 
518         case USBD_STATUS_NOT_SUPPORTED:
519             Status = STATUS_NOT_SUPPORTED;
520             break;
521 
522         case USBD_STATUS_INVALID_URB_FUNCTION:
523         case USBD_STATUS_INVALID_PARAMETER:
524         case USBD_STATUS_INVALID_PIPE_HANDLE:
525         case USBD_STATUS_BAD_START_FRAME:
526             Status = STATUS_INVALID_PARAMETER;
527             break;
528 
529         default:
530             if (USBD_ERROR(USBDStatus))
531                 Status = STATUS_UNSUCCESSFUL;
532             else
533                 Status = STATUS_SUCCESS;
534 
535             break;
536     }
537 
538     return Status;
539 }
540 
541 NTSTATUS
542 NTAPI
543 USBPORT_Wait(IN PVOID MiniPortExtension,
544              IN ULONG Milliseconds)
545 {
546     LARGE_INTEGER Interval = {{0, 0}};
547 
548     DPRINT("USBPORT_Wait: Milliseconds - %x\n", Milliseconds);
549     Interval.QuadPart -= 10000 * Milliseconds + (KeQueryTimeIncrement() - 1);
550     return KeDelayExecutionThread(KernelMode, FALSE, &Interval);
551 }
552 
553 VOID
554 NTAPI
555 USBPORT_MiniportInterrupts(IN PDEVICE_OBJECT FdoDevice,
556                            IN BOOLEAN IsEnable)
557 {
558     PUSBPORT_DEVICE_EXTENSION FdoExtension;
559     PUSBPORT_REGISTRATION_PACKET Packet;
560     BOOLEAN IsLock;
561     KIRQL OldIrql;
562 
563     DPRINT_INT("USBPORT_MiniportInterrupts: IsEnable - %p\n", IsEnable);
564 
565     FdoExtension = FdoDevice->DeviceExtension;
566     Packet = &FdoExtension->MiniPortInterface->Packet;
567 
568     IsLock = (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_NOT_LOCK_INT) == 0;
569 
570     if (IsLock)
571         KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
572 
573     if (IsEnable)
574     {
575         FdoExtension->Flags |= USBPORT_FLAG_INTERRUPT_ENABLED;
576         Packet->EnableInterrupts(FdoExtension->MiniPortExt);
577     }
578     else
579     {
580         Packet->DisableInterrupts(FdoExtension->MiniPortExt);
581         FdoExtension->Flags &= ~USBPORT_FLAG_INTERRUPT_ENABLED;
582     }
583 
584     if (IsLock)
585         KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
586 }
587 
588 VOID
589 NTAPI
590 USBPORT_SoftInterruptDpc(IN PRKDPC Dpc,
591                          IN PVOID DeferredContext,
592                          IN PVOID SystemArgument1,
593                          IN PVOID SystemArgument2)
594 {
595     PDEVICE_OBJECT FdoDevice;
596     PUSBPORT_DEVICE_EXTENSION FdoExtension;
597 
598     DPRINT_INT("USBPORT_SoftInterruptDpc: ...\n");
599 
600     FdoDevice = DeferredContext;
601     FdoExtension = FdoDevice->DeviceExtension;
602 
603     if (!KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, (PVOID)1))
604     {
605         InterlockedDecrement(&FdoExtension->IsrDpcCounter);
606     }
607 }
608 
609 VOID
610 NTAPI
611 USBPORT_SoftInterrupt(IN PDEVICE_OBJECT FdoDevice)
612 {
613     PUSBPORT_DEVICE_EXTENSION FdoExtension;
614     LARGE_INTEGER DueTime = {{0, 0}};
615 
616     DPRINT_INT("USBPORT_SoftInterrupt: ...\n");
617 
618     FdoExtension = FdoDevice->DeviceExtension;
619 
620     KeInitializeTimer(&FdoExtension->TimerSoftInterrupt);
621 
622     KeInitializeDpc(&FdoExtension->SoftInterruptDpc,
623                     USBPORT_SoftInterruptDpc,
624                     FdoDevice);
625 
626     DueTime.QuadPart -= 10000 + (KeQueryTimeIncrement() - 1);
627 
628     KeSetTimer(&FdoExtension->TimerSoftInterrupt,
629                DueTime,
630                &FdoExtension->SoftInterruptDpc);
631 }
632 
633 VOID
634 NTAPI
635 USBPORT_InvalidateControllerHandler(IN PDEVICE_OBJECT FdoDevice,
636                                     IN ULONG Type)
637 {
638     PUSBPORT_DEVICE_EXTENSION FdoExtension;
639 
640     DPRINT_CORE("USBPORT_InvalidateControllerHandler: Invalidate Type - %x\n",
641                 Type);
642 
643     FdoExtension = FdoDevice->DeviceExtension;
644 
645     switch (Type)
646     {
647         case USBPORT_INVALIDATE_CONTROLLER_RESET:
648             DPRINT1("USBPORT_InvalidateControllerHandler: INVALIDATE_CONTROLLER_RESET UNIMPLEMENTED. FIXME.\n");
649             break;
650 
651         case USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE:
652             DPRINT1("USBPORT_InvalidateControllerHandler: INVALIDATE_CONTROLLER_SURPRISE_REMOVE UNIMPLEMENTED. FIXME.\n");
653             break;
654 
655         case USBPORT_INVALIDATE_CONTROLLER_SOFT_INTERRUPT:
656             if (InterlockedIncrement(&FdoExtension->IsrDpcCounter))
657             {
658                 InterlockedDecrement(&FdoExtension->IsrDpcCounter);
659             }
660             else
661             {
662                 USBPORT_SoftInterrupt(FdoDevice);
663             }
664             break;
665     }
666 }
667 
668 ULONG
669 NTAPI
670 USBPORT_InvalidateController(IN PVOID MiniPortExtension,
671                              IN ULONG Type)
672 {
673     PUSBPORT_DEVICE_EXTENSION FdoExtension;
674     PDEVICE_OBJECT FdoDevice;
675 
676     DPRINT("USBPORT_InvalidateController: Invalidate Type - %x\n", Type);
677 
678     //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION));
679     FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
680                                                sizeof(USBPORT_DEVICE_EXTENSION));
681     FdoDevice = FdoExtension->CommonExtension.SelfDevice;
682 
683     USBPORT_InvalidateControllerHandler(FdoDevice, Type);
684 
685     return 0;
686 }
687 
688 ULONG
689 NTAPI
690 USBPORT_NotifyDoubleBuffer(IN PVOID MiniPortExtension,
691                            IN PVOID MiniPortTransfer,
692                            IN PVOID Buffer,
693                            IN SIZE_T Length)
694 {
695     DPRINT1("USBPORT_NotifyDoubleBuffer: UNIMPLEMENTED. FIXME.\n");
696     return 0;
697 }
698 
699 VOID
700 NTAPI
701 USBPORT_WorkerRequestDpc(IN PRKDPC Dpc,
702                          IN PVOID DeferredContext,
703                          IN PVOID SystemArgument1,
704                          IN PVOID SystemArgument2)
705 {
706     PDEVICE_OBJECT FdoDevice;
707     PUSBPORT_DEVICE_EXTENSION FdoExtension;
708 
709     DPRINT("USBPORT_WorkerRequestDpc: ...\n");
710 
711     FdoDevice = DeferredContext;
712     FdoExtension = FdoDevice->DeviceExtension;
713 
714     if (!InterlockedIncrement(&FdoExtension->IsrDpcHandlerCounter))
715     {
716         USBPORT_DpcHandler(FdoDevice);
717     }
718 
719     InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter);
720 }
721 
722 VOID
723 NTAPI
724 USBPORT_DoneTransfer(IN PUSBPORT_TRANSFER Transfer)
725 {
726     PUSBPORT_ENDPOINT          Endpoint;
727     PDEVICE_OBJECT             FdoDevice;
728     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
729     PURB                       Urb;
730     PIRP                       Irp;
731     KIRQL                      CancelIrql;
732     KIRQL                      OldIrql;
733 
734     DPRINT_CORE("USBPORT_DoneTransfer: Transfer - %p\n", Transfer);
735 
736     Endpoint = Transfer->Endpoint;
737     FdoDevice = Endpoint->FdoDevice;
738     FdoExtension = FdoDevice->DeviceExtension;
739 
740     Urb = Transfer->Urb;
741     Irp = Transfer->Irp;
742 
743     KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql);
744 
745     if (Irp)
746     {
747         IoAcquireCancelSpinLock(&CancelIrql);
748         IoSetCancelRoutine(Irp, NULL);
749         IoReleaseCancelSpinLock(CancelIrql);
750 
751         USBPORT_RemoveActiveTransferIrp(FdoDevice, Irp);
752     }
753 
754     KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql);
755 
756     USBPORT_USBDStatusToNtStatus(Transfer->Urb, Transfer->USBDStatus);
757     USBPORT_CompleteTransfer(Urb, Urb->UrbHeader.Status);
758 
759     DPRINT_CORE("USBPORT_DoneTransfer: exit\n");
760 }
761 
762 VOID
763 NTAPI
764 USBPORT_FlushDoneTransfers(IN PDEVICE_OBJECT FdoDevice)
765 {
766     PUSBPORT_DEVICE_EXTENSION FdoExtension;
767     PLIST_ENTRY DoneTransferList;
768     PUSBPORT_TRANSFER Transfer;
769     PUSBPORT_ENDPOINT Endpoint;
770     ULONG TransferCount;
771     KIRQL OldIrql;
772     BOOLEAN IsHasTransfers;
773 
774     DPRINT_CORE("USBPORT_FlushDoneTransfers: ...\n");
775 
776     FdoExtension = FdoDevice->DeviceExtension;
777     DoneTransferList = &FdoExtension->DoneTransferList;
778 
779     while (TRUE)
780     {
781         KeAcquireSpinLock(&FdoExtension->DoneTransferSpinLock, &OldIrql);
782 
783         if (IsListEmpty(DoneTransferList))
784             break;
785 
786         Transfer = CONTAINING_RECORD(DoneTransferList->Flink,
787                                      USBPORT_TRANSFER,
788                                      TransferLink);
789 
790         RemoveHeadList(DoneTransferList);
791         KeReleaseSpinLock(&FdoExtension->DoneTransferSpinLock, OldIrql);
792 
793         if (Transfer)
794         {
795             Endpoint = Transfer->Endpoint;
796 
797             if ((Transfer->Flags & TRANSFER_FLAG_SPLITED))
798             {
799                 USBPORT_DoneSplitTransfer(Transfer);
800             }
801             else
802             {
803                 USBPORT_DoneTransfer(Transfer);
804             }
805 
806             IsHasTransfers = USBPORT_EndpointHasQueuedTransfers(FdoDevice,
807                                                                 Endpoint,
808                                                                 &TransferCount);
809 
810             if (IsHasTransfers && !TransferCount)
811             {
812                 USBPORT_InvalidateEndpointHandler(FdoDevice,
813                                                   Endpoint,
814                                                   INVALIDATE_ENDPOINT_WORKER_DPC);
815             }
816         }
817     }
818 
819     KeReleaseSpinLock(&FdoExtension->DoneTransferSpinLock, OldIrql);
820 }
821 
822 
823 VOID
824 NTAPI
825 USBPORT_TransferFlushDpc(IN PRKDPC Dpc,
826                          IN PVOID DeferredContext,
827                          IN PVOID SystemArgument1,
828                          IN PVOID SystemArgument2)
829 {
830     PDEVICE_OBJECT FdoDevice;
831 
832     DPRINT_CORE("USBPORT_TransferFlushDpc: ...\n");
833     FdoDevice = DeferredContext;
834     USBPORT_FlushDoneTransfers(FdoDevice);
835 }
836 
837 BOOLEAN
838 NTAPI
839 USBPORT_QueueDoneTransfer(IN PUSBPORT_TRANSFER Transfer,
840                           IN USBD_STATUS USBDStatus)
841 {
842     PDEVICE_OBJECT FdoDevice;
843     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
844 
845     DPRINT_CORE("USBPORT_QueueDoneTransfer: Transfer - %p, USBDStatus - %p\n",
846                 Transfer,
847                 USBDStatus);
848 
849     FdoDevice = Transfer->Endpoint->FdoDevice;
850     FdoExtension = FdoDevice->DeviceExtension;
851 
852     RemoveEntryList(&Transfer->TransferLink);
853     Transfer->USBDStatus = USBDStatus;
854 
855     ExInterlockedInsertTailList(&FdoExtension->DoneTransferList,
856                                 &Transfer->TransferLink,
857                                 &FdoExtension->DoneTransferSpinLock);
858 
859     return KeInsertQueueDpc(&FdoExtension->TransferFlushDpc, NULL, NULL);
860 }
861 
862 VOID
863 NTAPI
864 USBPORT_DpcHandler(IN PDEVICE_OBJECT FdoDevice)
865 {
866     PUSBPORT_DEVICE_EXTENSION FdoExtension;
867     PUSBPORT_ENDPOINT Endpoint;
868     PLIST_ENTRY Entry;
869     LIST_ENTRY List;
870     LONG LockCounter;
871 
872     DPRINT_CORE("USBPORT_DpcHandler: ...\n");
873 
874     FdoExtension = FdoDevice->DeviceExtension;
875 
876     InitializeListHead(&List);
877 
878     KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
879     Entry = FdoExtension->EndpointList.Flink;
880 
881     while (Entry && Entry != &FdoExtension->EndpointList)
882     {
883         Endpoint = CONTAINING_RECORD(Entry,
884                                      USBPORT_ENDPOINT,
885                                      EndpointLink);
886 
887         LockCounter = InterlockedIncrement(&Endpoint->LockCounter);
888 
889         if (USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_ACTIVE ||
890             LockCounter ||
891             Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
892         {
893             InterlockedDecrement(&Endpoint->LockCounter);
894         }
895         else
896         {
897             InsertTailList(&List, &Endpoint->DispatchLink);
898 
899             if (Endpoint->WorkerLink.Flink && Endpoint->WorkerLink.Blink)
900             {
901                 RemoveEntryList(&Endpoint->WorkerLink);
902 
903                 Endpoint->WorkerLink.Flink = NULL;
904                 Endpoint->WorkerLink.Blink = NULL;
905             }
906         }
907 
908         Entry = Endpoint->EndpointLink.Flink;
909     }
910 
911     KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
912 
913     while (!IsListEmpty(&List))
914     {
915         Endpoint = CONTAINING_RECORD(List.Flink,
916                                      USBPORT_ENDPOINT,
917                                      DispatchLink);
918 
919         RemoveEntryList(List.Flink);
920         Endpoint->DispatchLink.Flink = NULL;
921         Endpoint->DispatchLink.Blink = NULL;
922 
923         USBPORT_EndpointWorker(Endpoint, TRUE);
924         USBPORT_FlushPendingTransfers(Endpoint);
925     }
926 
927     KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
928 
929     if (!IsListEmpty(&FdoExtension->WorkerList))
930     {
931         USBPORT_SignalWorkerThread(FdoDevice);
932     }
933 
934     KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
935 
936     USBPORT_FlushDoneTransfers(FdoDevice);
937 }
938 
939 VOID
940 NTAPI
941 USBPORT_IsrDpcHandler(IN PDEVICE_OBJECT FdoDevice,
942                       IN BOOLEAN IsDpcHandler)
943 {
944     PUSBPORT_DEVICE_EXTENSION FdoExtension;
945     PUSBPORT_REGISTRATION_PACKET Packet;
946     PUSBPORT_ENDPOINT Endpoint;
947     PLIST_ENTRY List;
948     ULONG FrameNumber;
949 
950     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
951 
952     DPRINT_CORE("USBPORT_IsrDpcHandler: IsDpcHandler - %x\n", IsDpcHandler);
953 
954     FdoExtension = FdoDevice->DeviceExtension;
955     Packet = &FdoExtension->MiniPortInterface->Packet;
956 
957     if (InterlockedIncrement(&FdoExtension->IsrDpcHandlerCounter))
958     {
959         KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL);
960         InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter);
961         return;
962     }
963 
964     for (List = ExInterlockedRemoveHeadList(&FdoExtension->EpStateChangeList,
965                                             &FdoExtension->EpStateChangeSpinLock);
966          List != NULL;
967          List = ExInterlockedRemoveHeadList(&FdoExtension->EpStateChangeList,
968                                             &FdoExtension->EpStateChangeSpinLock))
969     {
970         Endpoint = CONTAINING_RECORD(List,
971                                      USBPORT_ENDPOINT,
972                                      StateChangeLink);
973 
974         DPRINT_CORE("USBPORT_IsrDpcHandler: Endpoint - %p\n", Endpoint);
975 
976         KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock);
977 
978         KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
979         FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt);
980         KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
981 
982         if (FrameNumber <= Endpoint->FrameNumber &&
983             !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
984         {
985             KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
986 
987             ExInterlockedInsertHeadList(&FdoExtension->EpStateChangeList,
988                                         &Endpoint->StateChangeLink,
989                                         &FdoExtension->EpStateChangeSpinLock);
990 
991             KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
992             Packet->InterruptNextSOF(FdoExtension->MiniPortExt);
993             KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
994 
995             break;
996         }
997 
998         KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
999 
1000         KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1001         Endpoint->StateLast = Endpoint->StateNext;
1002         KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1003 
1004         DPRINT_CORE("USBPORT_IsrDpcHandler: Endpoint->StateLast - %x\n",
1005                     Endpoint->StateLast);
1006 
1007         if (IsDpcHandler)
1008         {
1009             USBPORT_InvalidateEndpointHandler(FdoDevice,
1010                                               Endpoint,
1011                                               INVALIDATE_ENDPOINT_ONLY);
1012         }
1013         else
1014         {
1015             USBPORT_InvalidateEndpointHandler(FdoDevice,
1016                                               Endpoint,
1017                                               INVALIDATE_ENDPOINT_WORKER_THREAD);
1018         }
1019     }
1020 
1021     if (IsDpcHandler)
1022     {
1023         USBPORT_DpcHandler(FdoDevice);
1024     }
1025 
1026     InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter);
1027 }
1028 
1029 VOID
1030 NTAPI
1031 USBPORT_IsrDpc(IN PRKDPC Dpc,
1032                IN PVOID DeferredContext,
1033                IN PVOID SystemArgument1,
1034                IN PVOID SystemArgument2)
1035 {
1036     PDEVICE_OBJECT FdoDevice;
1037     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1038     PUSBPORT_REGISTRATION_PACKET Packet;
1039     BOOLEAN InterruptEnable;
1040 
1041     DPRINT_INT("USBPORT_IsrDpc: DeferredContext - %p, SystemArgument2 - %p\n",
1042                DeferredContext,
1043                SystemArgument2);
1044 
1045     FdoDevice = DeferredContext;
1046     FdoExtension = FdoDevice->DeviceExtension;
1047     Packet = &FdoExtension->MiniPortInterface->Packet;
1048 
1049     if (SystemArgument2)
1050     {
1051         InterlockedDecrement(&FdoExtension->IsrDpcCounter);
1052     }
1053 
1054     KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportInterruptsSpinLock);
1055     InterruptEnable = (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED) ==
1056                        USBPORT_FLAG_INTERRUPT_ENABLED;
1057 
1058     Packet->InterruptDpc(FdoExtension->MiniPortExt, InterruptEnable);
1059 
1060     KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportInterruptsSpinLock);
1061 
1062     if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND &&
1063         FdoExtension->TimerFlags & USBPORT_TMFLAG_WAKE)
1064     {
1065         USBPORT_CompletePdoWaitWake(FdoDevice);
1066     }
1067     else
1068     {
1069         USBPORT_IsrDpcHandler(FdoDevice, TRUE);
1070     }
1071 
1072     DPRINT_INT("USBPORT_IsrDpc: exit\n");
1073 }
1074 
1075 BOOLEAN
1076 NTAPI
1077 USBPORT_InterruptService(IN PKINTERRUPT Interrupt,
1078                          IN PVOID ServiceContext)
1079 {
1080     PDEVICE_OBJECT FdoDevice;
1081     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1082     PUSBPORT_REGISTRATION_PACKET Packet;
1083     BOOLEAN Result = FALSE;
1084 
1085     FdoDevice = ServiceContext;
1086     FdoExtension = FdoDevice->DeviceExtension;
1087     Packet = &FdoExtension->MiniPortInterface->Packet;
1088 
1089     DPRINT_INT("USBPORT_InterruptService: FdoExtension[%p]->Flags - %08X\n",
1090            FdoExtension,
1091            FdoExtension->Flags);
1092 
1093     if (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED &&
1094         FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED)
1095     {
1096         Result = Packet->InterruptService(FdoExtension->MiniPortExt);
1097 
1098         if (Result)
1099         {
1100             KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL);
1101         }
1102     }
1103 
1104     DPRINT_INT("USBPORT_InterruptService: return - %x\n", Result);
1105 
1106     return Result;
1107 }
1108 
1109 VOID
1110 NTAPI
1111 USBPORT_SignalWorkerThread(IN PDEVICE_OBJECT FdoDevice)
1112 {
1113     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1114     KIRQL OldIrql;
1115 
1116     DPRINT_CORE("USBPORT_SignalWorkerThread ...\n");
1117 
1118     FdoExtension = FdoDevice->DeviceExtension;
1119 
1120     KeAcquireSpinLock(&FdoExtension->WorkerThreadEventSpinLock, &OldIrql);
1121     KeSetEvent(&FdoExtension->WorkerThreadEvent, EVENT_INCREMENT, FALSE);
1122     KeReleaseSpinLock(&FdoExtension->WorkerThreadEventSpinLock, OldIrql);
1123 }
1124 
1125 VOID
1126 NTAPI
1127 USBPORT_WorkerThreadHandler(IN PDEVICE_OBJECT FdoDevice)
1128 {
1129     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1130     PUSBPORT_REGISTRATION_PACKET Packet;
1131     PLIST_ENTRY workerList;
1132     KIRQL OldIrql;
1133     PUSBPORT_ENDPOINT Endpoint;
1134     LIST_ENTRY list;
1135     BOOLEAN Result;
1136 
1137     DPRINT_CORE("USBPORT_WorkerThreadHandler: ...\n");
1138 
1139     FdoExtension = FdoDevice->DeviceExtension;
1140     Packet = &FdoExtension->MiniPortInterface->Packet;
1141 
1142     KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1143 
1144     if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND))
1145     {
1146         Packet->CheckController(FdoExtension->MiniPortExt);
1147     }
1148 
1149     KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1150 
1151     InitializeListHead(&list);
1152 
1153     USBPORT_FlushAllEndpoints(FdoDevice);
1154 
1155     while (TRUE)
1156     {
1157         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1158         KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
1159 
1160         workerList = &FdoExtension->WorkerList;
1161 
1162         if (IsListEmpty(workerList))
1163             break;
1164 
1165         Endpoint = CONTAINING_RECORD(workerList->Flink,
1166                                      USBPORT_ENDPOINT,
1167                                      WorkerLink);
1168 
1169         DPRINT_CORE("USBPORT_WorkerThreadHandler: Endpoint - %p\n", Endpoint);
1170 
1171         RemoveHeadList(workerList);
1172         Endpoint->WorkerLink.Blink = NULL;
1173         Endpoint->WorkerLink.Flink = NULL;
1174 
1175         KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
1176 
1177         Result = USBPORT_EndpointWorker(Endpoint, FALSE);
1178         KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
1179 
1180         if (Result)
1181         {
1182             if (Endpoint->FlushAbortLink.Flink == NULL ||
1183                 Endpoint->FlushAbortLink.Blink == NULL)
1184             {
1185                 InsertTailList(&list, &Endpoint->FlushAbortLink);
1186             }
1187         }
1188 
1189         while (!IsListEmpty(&list))
1190         {
1191             Endpoint = CONTAINING_RECORD(list.Flink,
1192                                          USBPORT_ENDPOINT,
1193                                          FlushAbortLink);
1194 
1195             RemoveHeadList(&list);
1196 
1197             Endpoint->FlushAbortLink.Flink = NULL;
1198             Endpoint->FlushAbortLink.Blink = NULL;
1199 
1200             if (Endpoint->WorkerLink.Flink == NULL ||
1201                 Endpoint->WorkerLink.Blink == NULL)
1202             {
1203                 InsertTailList(&FdoExtension->WorkerList,
1204                                &Endpoint->WorkerLink);
1205 
1206                 USBPORT_SignalWorkerThread(FdoDevice);
1207             }
1208         }
1209 
1210         KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
1211         KeLowerIrql(OldIrql);
1212     }
1213 
1214     KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
1215     KeLowerIrql(OldIrql);
1216 
1217     USBPORT_FlushClosedEndpointList(FdoDevice);
1218 }
1219 
1220 VOID
1221 NTAPI
1222 USBPORT_DoRootHubCallback(IN PDEVICE_OBJECT FdoDevice)
1223 {
1224     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1225     PDEVICE_OBJECT PdoDevice;
1226     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
1227     PRH_INIT_CALLBACK RootHubInitCallback;
1228     PVOID RootHubInitContext;
1229 
1230     FdoExtension = FdoDevice->DeviceExtension;
1231 
1232     DPRINT("USBPORT_DoRootHubCallback: FdoDevice - %p\n", FdoDevice);
1233 
1234     PdoDevice = FdoExtension->RootHubPdo;
1235 
1236     if (PdoDevice)
1237     {
1238         PdoExtension = PdoDevice->DeviceExtension;
1239 
1240         RootHubInitContext = PdoExtension->RootHubInitContext;
1241         RootHubInitCallback = PdoExtension->RootHubInitCallback;
1242 
1243         PdoExtension->RootHubInitCallback = NULL;
1244         PdoExtension->RootHubInitContext = NULL;
1245 
1246         if (RootHubInitCallback)
1247         {
1248             RootHubInitCallback(RootHubInitContext);
1249         }
1250     }
1251 
1252     DPRINT("USBPORT_DoRootHubCallback: exit\n");
1253 }
1254 
1255 VOID
1256 NTAPI
1257 USBPORT_SynchronizeRootHubCallback(IN PDEVICE_OBJECT FdoDevice,
1258                                    IN PDEVICE_OBJECT Usb2FdoDevice)
1259 {
1260     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1261     PUSBPORT_REGISTRATION_PACKET Packet;
1262     PUSBPORT_DEVICE_EXTENSION Usb2FdoExtension;
1263     PDEVICE_RELATIONS CompanionControllersList;
1264     PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension;
1265     PDEVICE_OBJECT * Entry;
1266     ULONG ix;
1267 
1268     DPRINT("USBPORT_SynchronizeRootHubCallback: FdoDevice - %p, Usb2FdoDevice - %p\n",
1269            FdoDevice,
1270            Usb2FdoDevice);
1271 
1272     FdoExtension = FdoDevice->DeviceExtension;
1273     Packet = &FdoExtension->MiniPortInterface->Packet;
1274 
1275     if (Usb2FdoDevice == NULL &&
1276         !(Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2))
1277     {
1278         /* Not Companion USB11 Controller */
1279         USBPORT_DoRootHubCallback(FdoDevice);
1280 
1281         FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK;
1282         InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1);
1283 
1284         DPRINT("USBPORT_SynchronizeRootHubCallback: exit\n");
1285         return;
1286     }
1287 
1288     /* USB2 or Companion USB11 */
1289 
1290     DPRINT("USBPORT_SynchronizeRootHubCallback: FdoExtension->Flags - %p\n",
1291            FdoExtension->Flags);
1292 
1293     if (!(FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC))
1294     {
1295         KeWaitForSingleObject(&FdoExtension->ControllerSemaphore,
1296                               Executive,
1297                               KernelMode,
1298                               FALSE,
1299                               NULL);
1300 
1301         FdoExtension->Flags |= USBPORT_FLAG_PWR_AND_CHIRP_LOCK;
1302 
1303         if (!(FdoExtension->Flags & (USBPORT_FLAG_HC_SUSPEND |
1304                                      USBPORT_FLAG_POWER_AND_CHIRP_OK)))
1305         {
1306             USBPORT_RootHubPowerAndChirpAllCcPorts(FdoDevice);
1307             FdoExtension->Flags |= USBPORT_FLAG_POWER_AND_CHIRP_OK;
1308         }
1309 
1310         FdoExtension->Flags &= ~USBPORT_FLAG_PWR_AND_CHIRP_LOCK;
1311 
1312         KeReleaseSemaphore(&FdoExtension->ControllerSemaphore,
1313                            LOW_REALTIME_PRIORITY,
1314                            1,
1315                            FALSE);
1316 
1317         CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice,
1318                                                                     FALSE,
1319                                                                     TRUE);
1320 
1321         if (CompanionControllersList)
1322         {
1323             Entry = &CompanionControllersList->Objects[0];
1324 
1325             for (ix = 0; ix < CompanionControllersList->Count; ++ix)
1326             {
1327                 CompanionFdoExtension = ((*Entry)->DeviceExtension);
1328 
1329                 InterlockedCompareExchange(&CompanionFdoExtension->RHInitCallBackLock,
1330                                            0,
1331                                            1);
1332 
1333                 ++Entry;
1334             }
1335 
1336             ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG);
1337         }
1338 
1339         USBPORT_DoRootHubCallback(FdoDevice);
1340 
1341         FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK;
1342         InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1);
1343     }
1344     else
1345     {
1346         Usb2FdoExtension = Usb2FdoDevice->DeviceExtension;
1347 
1348         USBPORT_Wait(FdoDevice, 50);
1349 
1350         while (FdoExtension->RHInitCallBackLock)
1351         {
1352             USBPORT_Wait(FdoDevice, 10);
1353 
1354             Usb2FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK;
1355             USBPORT_SignalWorkerThread(Usb2FdoDevice);
1356         }
1357 
1358         USBPORT_DoRootHubCallback(FdoDevice);
1359 
1360         FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK;
1361     }
1362 
1363     DPRINT("USBPORT_SynchronizeRootHubCallback: exit\n");
1364 }
1365 
1366 VOID
1367 NTAPI
1368 USBPORT_WorkerThread(IN PVOID StartContext)
1369 {
1370     PDEVICE_OBJECT FdoDevice;
1371     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1372     LARGE_INTEGER OldTime;
1373     LARGE_INTEGER NewTime;
1374     KIRQL OldIrql;
1375 
1376     DPRINT_CORE("USBPORT_WorkerThread ...\n");
1377 
1378     FdoDevice = StartContext;
1379     FdoExtension = FdoDevice->DeviceExtension;
1380 
1381     FdoExtension->WorkerThread = KeGetCurrentThread();
1382 
1383     do
1384     {
1385         KeQuerySystemTime(&OldTime);
1386 
1387         KeWaitForSingleObject(&FdoExtension->WorkerThreadEvent,
1388                               Suspended,
1389                               KernelMode,
1390                               FALSE,
1391                               NULL);
1392 
1393         if (FdoExtension->Flags & USBPORT_FLAG_WORKER_THREAD_EXIT)
1394         {
1395             break;
1396         }
1397 
1398         KeQuerySystemTime(&NewTime);
1399 
1400         KeAcquireSpinLock(&FdoExtension->WorkerThreadEventSpinLock, &OldIrql);
1401         KeClearEvent(&FdoExtension->WorkerThreadEvent);
1402         KeReleaseSpinLock(&FdoExtension->WorkerThreadEventSpinLock, OldIrql);
1403         DPRINT_CORE("USBPORT_WorkerThread: run\n");
1404 
1405         if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED)
1406         {
1407             USBPORT_DoSetPowerD0(FdoDevice);
1408 
1409             if (FdoExtension->Flags & USBPORT_FLAG_RH_INIT_CALLBACK)
1410             {
1411                 PDEVICE_OBJECT USB2FdoDevice = NULL;
1412 
1413                 USB2FdoDevice = USBPORT_FindUSB2Controller(FdoDevice);
1414                 USBPORT_SynchronizeRootHubCallback(FdoDevice, USB2FdoDevice);
1415             }
1416         }
1417 
1418         USBPORT_WorkerThreadHandler(FdoDevice);
1419     }
1420     while (!(FdoExtension->Flags & USBPORT_FLAG_WORKER_THREAD_ON));
1421 
1422     PsTerminateSystemThread(0);
1423 }
1424 
1425 NTSTATUS
1426 NTAPI
1427 USBPORT_CreateWorkerThread(IN PDEVICE_OBJECT FdoDevice)
1428 {
1429     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1430     NTSTATUS Status;
1431 
1432     DPRINT("USBPORT_CreateWorkerThread ...\n");
1433 
1434     FdoExtension = FdoDevice->DeviceExtension;
1435 
1436     FdoExtension->Flags &= ~USBPORT_FLAG_WORKER_THREAD_ON;
1437 
1438     KeInitializeEvent(&FdoExtension->WorkerThreadEvent,
1439                       NotificationEvent,
1440                       FALSE);
1441 
1442     Status = PsCreateSystemThread(&FdoExtension->WorkerThreadHandle,
1443                                   THREAD_ALL_ACCESS,
1444                                   NULL,
1445                                   NULL,
1446                                   NULL,
1447                                   USBPORT_WorkerThread,
1448                                   (PVOID)FdoDevice);
1449 
1450     return Status;
1451 }
1452 
1453 VOID
1454 NTAPI
1455 USBPORT_StopWorkerThread(IN PDEVICE_OBJECT FdoDevice)
1456 {
1457     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1458     NTSTATUS Status;
1459 
1460     DPRINT("USBPORT_StopWorkerThread ...\n");
1461 
1462     FdoExtension = FdoDevice->DeviceExtension;
1463 
1464     FdoExtension->Flags |= USBPORT_FLAG_WORKER_THREAD_EXIT;
1465     USBPORT_SignalWorkerThread(FdoDevice);
1466     Status = ZwWaitForSingleObject(FdoExtension->WorkerThreadHandle, FALSE, NULL);
1467     NT_ASSERT(Status == STATUS_SUCCESS);
1468 }
1469 
1470 VOID
1471 NTAPI
1472 USBPORT_SynchronizeControllersStart(IN PDEVICE_OBJECT FdoDevice)
1473 {
1474     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1475     PDEVICE_OBJECT PdoDevice;
1476     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
1477     PDEVICE_OBJECT USB2FdoDevice = NULL;
1478     PUSBPORT_DEVICE_EXTENSION USB2FdoExtension;
1479     BOOLEAN IsOn;
1480 
1481     DPRINT_TIMER("USBPORT_SynchronizeControllersStart: FdoDevice - %p\n",
1482                  FdoDevice);
1483 
1484     FdoExtension = FdoDevice->DeviceExtension;
1485 
1486     PdoDevice = FdoExtension->RootHubPdo;
1487 
1488     if (!PdoDevice)
1489     {
1490         return;
1491     }
1492 
1493     PdoExtension = PdoDevice->DeviceExtension;
1494 
1495     if (PdoExtension->RootHubInitCallback == NULL ||
1496         FdoExtension->Flags & USBPORT_FLAG_RH_INIT_CALLBACK)
1497     {
1498         return;
1499     }
1500 
1501     DPRINT_TIMER("USBPORT_SynchronizeControllersStart: Flags - %p\n",
1502                  FdoExtension->Flags);
1503 
1504     if (FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC)
1505     {
1506         IsOn = FALSE;
1507 
1508         USB2FdoDevice = USBPORT_FindUSB2Controller(FdoDevice);
1509 
1510         DPRINT_TIMER("USBPORT_SynchronizeControllersStart: USB2FdoDevice - %p\n",
1511                      USB2FdoDevice);
1512 
1513         if (USB2FdoDevice)
1514         {
1515             USB2FdoExtension = USB2FdoDevice->DeviceExtension;
1516 
1517             if (USB2FdoExtension->CommonExtension.PnpStateFlags &
1518                 USBPORT_PNP_STATE_STARTED)
1519             {
1520                 IsOn = TRUE;
1521             }
1522         }
1523 
1524         if (!(FdoExtension->Flags & USBPORT_FLAG_NO_HACTION))
1525         {
1526             goto Start;
1527         }
1528 
1529         USB2FdoDevice = NULL;
1530     }
1531 
1532     IsOn = TRUE;
1533 
1534   Start:
1535 
1536     if (IsOn &&
1537         !InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 1, 0))
1538     {
1539         FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK;
1540         USBPORT_SignalWorkerThread(FdoDevice);
1541 
1542         if (USB2FdoDevice)
1543         {
1544             USB2FdoExtension = USB2FdoDevice->DeviceExtension;
1545 
1546             USB2FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK;
1547             USBPORT_SignalWorkerThread(USB2FdoDevice);
1548         }
1549     }
1550 
1551     DPRINT_TIMER("USBPORT_SynchronizeControllersStart: exit\n");
1552 }
1553 
1554 VOID
1555 NTAPI
1556 USBPORT_TimerDpc(IN PRKDPC Dpc,
1557                  IN PVOID DeferredContext,
1558                  IN PVOID SystemArgument1,
1559                  IN PVOID SystemArgument2)
1560 {
1561     PDEVICE_OBJECT FdoDevice;
1562     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1563     PUSBPORT_REGISTRATION_PACKET Packet;
1564     LARGE_INTEGER DueTime = {{0, 0}};
1565     ULONG TimerFlags;
1566     PTIMER_WORK_QUEUE_ITEM IdleQueueItem;
1567     KIRQL OldIrql;
1568     KIRQL TimerOldIrql;
1569 
1570     DPRINT_TIMER("USBPORT_TimerDpc: Dpc - %p, DeferredContext - %p\n",
1571            Dpc,
1572            DeferredContext);
1573 
1574     FdoDevice = DeferredContext;
1575     FdoExtension = FdoDevice->DeviceExtension;
1576     Packet = &FdoExtension->MiniPortInterface->Packet;
1577 
1578     KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &TimerOldIrql);
1579 
1580     TimerFlags = FdoExtension->TimerFlags;
1581 
1582     DPRINT_TIMER("USBPORT_TimerDpc: Flags - %p, TimerFlags - %p\n",
1583                  FdoExtension->Flags,
1584                  TimerFlags);
1585 
1586     if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND &&
1587         FdoExtension->Flags & USBPORT_FLAG_HC_WAKE_SUPPORT &&
1588         !(TimerFlags & USBPORT_TMFLAG_HC_RESUME))
1589     {
1590         KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1591         Packet->PollController(FdoExtension->MiniPortExt);
1592         KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1593     }
1594 
1595     USBPORT_SynchronizeControllersStart(FdoDevice);
1596 
1597     if (TimerFlags & USBPORT_TMFLAG_HC_SUSPENDED)
1598     {
1599         USBPORT_BadRequestFlush(FdoDevice);
1600         goto Exit;
1601     }
1602 
1603     KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1604 
1605     if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND))
1606     {
1607         Packet->CheckController(FdoExtension->MiniPortExt);
1608     }
1609 
1610     KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1611 
1612     if (FdoExtension->Flags & USBPORT_FLAG_HC_POLLING)
1613     {
1614         KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1615         Packet->PollController(FdoExtension->MiniPortExt);
1616         KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1617     }
1618 
1619     USBPORT_IsrDpcHandler(FdoDevice, FALSE);
1620 
1621     DPRINT_TIMER("USBPORT_TimerDpc: USBPORT_TimeoutAllEndpoints UNIMPLEMENTED.\n");
1622     //USBPORT_TimeoutAllEndpoints(FdoDevice);
1623     DPRINT_TIMER("USBPORT_TimerDpc: USBPORT_CheckIdleEndpoints UNIMPLEMENTED.\n");
1624     //USBPORT_CheckIdleEndpoints(FdoDevice);
1625 
1626     USBPORT_BadRequestFlush(FdoDevice);
1627 
1628     if (FdoExtension->IdleLockCounter > -1 &&
1629         !(TimerFlags & USBPORT_TMFLAG_IDLE_QUEUEITEM_ON))
1630     {
1631         IdleQueueItem = ExAllocatePoolWithTag(NonPagedPool,
1632                                               sizeof(TIMER_WORK_QUEUE_ITEM),
1633                                               USB_PORT_TAG);
1634 
1635         DPRINT("USBPORT_TimerDpc: IdleLockCounter - %x, IdleQueueItem - %p\n",
1636                FdoExtension->IdleLockCounter,
1637                IdleQueueItem);
1638 
1639         if (IdleQueueItem)
1640         {
1641             RtlZeroMemory(IdleQueueItem, sizeof(TIMER_WORK_QUEUE_ITEM));
1642 
1643             IdleQueueItem->WqItem.List.Flink = NULL;
1644             IdleQueueItem->WqItem.WorkerRoutine = USBPORT_DoIdleNotificationCallback;
1645             IdleQueueItem->WqItem.Parameter = IdleQueueItem;
1646 
1647             IdleQueueItem->FdoDevice = FdoDevice;
1648             IdleQueueItem->Context = 0;
1649 
1650             FdoExtension->TimerFlags |= USBPORT_TMFLAG_IDLE_QUEUEITEM_ON;
1651 
1652             ExQueueWorkItem(&IdleQueueItem->WqItem, CriticalWorkQueue);
1653         }
1654     }
1655 
1656 Exit:
1657 
1658     KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, TimerOldIrql);
1659 
1660     if (TimerFlags & USBPORT_TMFLAG_TIMER_QUEUED)
1661     {
1662         DueTime.QuadPart -= FdoExtension->TimerValue * 10000 +
1663                             (KeQueryTimeIncrement() - 1);
1664 
1665         KeSetTimer(&FdoExtension->TimerObject,
1666                    DueTime,
1667                    &FdoExtension->TimerDpc);
1668     }
1669 
1670     DPRINT_TIMER("USBPORT_TimerDpc: exit\n");
1671 }
1672 
1673 BOOLEAN
1674 NTAPI
1675 USBPORT_StartTimer(IN PDEVICE_OBJECT FdoDevice,
1676                    IN ULONG Time)
1677 {
1678     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1679     LARGE_INTEGER DueTime = {{0, 0}};
1680     ULONG TimeIncrement;
1681     BOOLEAN Result;
1682 
1683     DPRINT_TIMER("USBPORT_StartTimer: FdoDevice - %p, Time - %x\n",
1684            FdoDevice,
1685            Time);
1686 
1687     FdoExtension = FdoDevice->DeviceExtension;
1688 
1689     TimeIncrement = KeQueryTimeIncrement();
1690 
1691     FdoExtension->TimerFlags |= USBPORT_TMFLAG_TIMER_QUEUED;
1692     FdoExtension->TimerValue = Time;
1693 
1694     KeInitializeTimer(&FdoExtension->TimerObject);
1695     KeInitializeDpc(&FdoExtension->TimerDpc, USBPORT_TimerDpc, FdoDevice);
1696 
1697     DueTime.QuadPart -= 10000 * Time + (TimeIncrement - 1);
1698 
1699     Result = KeSetTimer(&FdoExtension->TimerObject,
1700                         DueTime,
1701                         &FdoExtension->TimerDpc);
1702 
1703     return Result;
1704 }
1705 
1706 PUSBPORT_COMMON_BUFFER_HEADER
1707 NTAPI
1708 USBPORT_AllocateCommonBuffer(IN PDEVICE_OBJECT FdoDevice,
1709                              IN SIZE_T BufferLength)
1710 {
1711     PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer = NULL;
1712     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1713     PDMA_ADAPTER DmaAdapter;
1714     PDMA_OPERATIONS DmaOperations;
1715     SIZE_T HeaderSize;
1716     ULONG Length = 0;
1717     ULONG LengthPadded;
1718     PHYSICAL_ADDRESS LogicalAddress;
1719     ULONG_PTR BaseVA;
1720     ULONG_PTR StartBufferVA;
1721     ULONG StartBufferPA;
1722 
1723     DPRINT("USBPORT_AllocateCommonBuffer: FdoDevice - %p, BufferLength - %p\n",
1724            FdoDevice,
1725            BufferLength);
1726 
1727     if (BufferLength == 0)
1728         goto Exit;
1729 
1730     FdoExtension = FdoDevice->DeviceExtension;
1731 
1732     DmaAdapter = FdoExtension->DmaAdapter;
1733     DmaOperations = DmaAdapter->DmaOperations;
1734 
1735     HeaderSize = sizeof(USBPORT_COMMON_BUFFER_HEADER);
1736     Length = ROUND_TO_PAGES(BufferLength + HeaderSize);
1737     LengthPadded = Length - (BufferLength + HeaderSize);
1738 
1739     BaseVA = (ULONG_PTR)DmaOperations->AllocateCommonBuffer(DmaAdapter,
1740                                                             Length,
1741                                                             &LogicalAddress,
1742                                                             TRUE);
1743 
1744     if (!BaseVA)
1745         goto Exit;
1746 
1747     StartBufferVA = BaseVA & ~(PAGE_SIZE - 1);
1748     StartBufferPA = LogicalAddress.LowPart & ~(PAGE_SIZE - 1);
1749 
1750     HeaderBuffer = (PUSBPORT_COMMON_BUFFER_HEADER)(StartBufferVA +
1751                                                    BufferLength +
1752                                                    LengthPadded);
1753 
1754     HeaderBuffer->Length = Length;
1755     HeaderBuffer->BaseVA = BaseVA;
1756     HeaderBuffer->LogicalAddress = LogicalAddress;
1757 
1758     HeaderBuffer->BufferLength = BufferLength + LengthPadded;
1759     HeaderBuffer->VirtualAddress = StartBufferVA;
1760     HeaderBuffer->PhysicalAddress = StartBufferPA;
1761 
1762     RtlZeroMemory((PVOID)StartBufferVA, BufferLength + LengthPadded);
1763 
1764 Exit:
1765     return HeaderBuffer;
1766 }
1767 
1768 VOID
1769 NTAPI
1770 USBPORT_FreeCommonBuffer(IN PDEVICE_OBJECT FdoDevice,
1771                          IN PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer)
1772 {
1773     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1774     PDMA_ADAPTER DmaAdapter;
1775     PDMA_OPERATIONS DmaOperations;
1776 
1777     DPRINT("USBPORT_FreeCommonBuffer: ...\n");
1778 
1779     FdoExtension = FdoDevice->DeviceExtension;
1780 
1781     DmaAdapter = FdoExtension->DmaAdapter;
1782     DmaOperations = DmaAdapter->DmaOperations;
1783 
1784     DmaOperations->FreeCommonBuffer(FdoExtension->DmaAdapter,
1785                                     HeaderBuffer->Length,
1786                                     HeaderBuffer->LogicalAddress,
1787                                     (PVOID)HeaderBuffer->VirtualAddress,
1788                                     TRUE);
1789 }
1790 
1791 PUSBPORT_MINIPORT_INTERFACE
1792 NTAPI
1793 USBPORT_FindMiniPort(IN PDRIVER_OBJECT DriverObject)
1794 {
1795     KIRQL OldIrql;
1796     PLIST_ENTRY List;
1797     PUSBPORT_MINIPORT_INTERFACE MiniPortInterface;
1798     BOOLEAN IsFound = FALSE;
1799 
1800     DPRINT("USBPORT_FindMiniPort: ...\n");
1801 
1802     KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql);
1803 
1804     for (List = USBPORT_MiniPortDrivers.Flink;
1805          List != &USBPORT_MiniPortDrivers;
1806          List = List->Flink)
1807     {
1808         MiniPortInterface = CONTAINING_RECORD(List,
1809                                               USBPORT_MINIPORT_INTERFACE,
1810                                               DriverLink);
1811 
1812         if (MiniPortInterface->DriverObject == DriverObject)
1813         {
1814             DPRINT("USBPORT_FindMiniPort: find MiniPortInterface - %p\n",
1815                    MiniPortInterface);
1816 
1817             IsFound = TRUE;
1818             break;
1819         }
1820     }
1821 
1822     KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql);
1823 
1824     if (IsFound)
1825         return MiniPortInterface;
1826     else
1827         return NULL;
1828 
1829 }
1830 
1831 NTSTATUS
1832 NTAPI
1833 USBPORT_AddDevice(IN PDRIVER_OBJECT DriverObject,
1834                   IN PDEVICE_OBJECT PhysicalDeviceObject)
1835 {
1836     NTSTATUS Status;
1837     PUSBPORT_MINIPORT_INTERFACE MiniPortInterface;
1838     ULONG DeviceNumber = 0;
1839     WCHAR CharDeviceName[64];
1840     UNICODE_STRING DeviceName;
1841     PDEVICE_OBJECT DeviceObject;
1842     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1843     PUSBPORT_COMMON_DEVICE_EXTENSION FdoCommonExtension;
1844     PDEVICE_OBJECT LowerDevice;
1845     ULONG Length;
1846 
1847     DPRINT("USBPORT_AddDevice: DriverObject - %p, PhysicalDeviceObject - %p\n",
1848            DriverObject,
1849            PhysicalDeviceObject);
1850 
1851     MiniPortInterface = USBPORT_FindMiniPort(DriverObject);
1852 
1853     if (!MiniPortInterface)
1854     {
1855         DPRINT("USBPORT_AddDevice: USBPORT_FindMiniPort not found MiniPortInterface\n");
1856         return STATUS_UNSUCCESSFUL;
1857     }
1858 
1859     while (TRUE)
1860     {
1861         /* Construct device name */
1862         RtlStringCbPrintfW(CharDeviceName,
1863                            sizeof(CharDeviceName),
1864                            L"\\Device\\USBFDO-%d",
1865                            DeviceNumber);
1866 
1867         RtlInitUnicodeString(&DeviceName, CharDeviceName);
1868 
1869         ASSERT(MiniPortInterface->Packet.MiniPortExtensionSize <=
1870                MAXULONG - sizeof(USBPORT_DEVICE_EXTENSION) - sizeof(USB2_HC_EXTENSION));
1871         Length = (ULONG)(sizeof(USBPORT_DEVICE_EXTENSION) +
1872                          MiniPortInterface->Packet.MiniPortExtensionSize +
1873                          sizeof(USB2_HC_EXTENSION));
1874 
1875         /* Create device */
1876         Status = IoCreateDevice(DriverObject,
1877                                 Length,
1878                                 &DeviceName,
1879                                 FILE_DEVICE_CONTROLLER,
1880                                 0,
1881                                 FALSE,
1882                                 &DeviceObject);
1883 
1884         /* Check for success */
1885         if (NT_SUCCESS(Status)) break;
1886 
1887         /* Is there a device object with that same name */
1888         if ((Status == STATUS_OBJECT_NAME_EXISTS) ||
1889             (Status == STATUS_OBJECT_NAME_COLLISION))
1890         {
1891             /* Try the next name */
1892             DeviceNumber++;
1893             continue;
1894         }
1895 
1896         /* Bail out on other errors */
1897         if (!NT_SUCCESS(Status))
1898         {
1899             DPRINT1("USBPORT_AddDevice: failed to create %wZ, Status %x\n",
1900                     &DeviceName,
1901                     Status);
1902 
1903             return Status;
1904         }
1905     }
1906 
1907     DPRINT("USBPORT_AddDevice: created device %p <%wZ>, Status %x\n",
1908            DeviceObject,
1909            &DeviceName,
1910            Status);
1911 
1912     FdoExtension = DeviceObject->DeviceExtension;
1913     FdoCommonExtension = &FdoExtension->CommonExtension;
1914 
1915     RtlZeroMemory(FdoExtension, sizeof(USBPORT_DEVICE_EXTENSION));
1916 
1917     FdoCommonExtension->SelfDevice = DeviceObject;
1918     FdoCommonExtension->LowerPdoDevice = PhysicalDeviceObject;
1919     FdoCommonExtension->IsPDO = FALSE;
1920 
1921     LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject,
1922                                               PhysicalDeviceObject);
1923 
1924     FdoCommonExtension->LowerDevice = LowerDevice;
1925 
1926     FdoCommonExtension->DevicePowerState = PowerDeviceD3;
1927 
1928     FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension +
1929                                         sizeof(USBPORT_DEVICE_EXTENSION));
1930 
1931     if (MiniPortInterface->Packet.MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
1932     {
1933         FdoExtension->Usb2Extension =
1934         (PUSB2_HC_EXTENSION)((ULONG_PTR)FdoExtension->MiniPortExt +
1935                              MiniPortInterface->Packet.MiniPortExtensionSize);
1936 
1937         DPRINT("USBPORT_AddDevice: Usb2Extension - %p\n",
1938                FdoExtension->Usb2Extension);
1939 
1940         USB2_InitController(FdoExtension->Usb2Extension);
1941     }
1942     else
1943     {
1944         FdoExtension->Usb2Extension = NULL;
1945     }
1946 
1947     FdoExtension->MiniPortInterface = MiniPortInterface;
1948     FdoExtension->FdoNameNumber = DeviceNumber;
1949 
1950     KeInitializeSemaphore(&FdoExtension->DeviceSemaphore, 1, 1);
1951     KeInitializeSemaphore(&FdoExtension->ControllerSemaphore, 1, 1);
1952 
1953     InitializeListHead(&FdoExtension->EndpointList);
1954     InitializeListHead(&FdoExtension->DoneTransferList);
1955     InitializeListHead(&FdoExtension->WorkerList);
1956     InitializeListHead(&FdoExtension->EpStateChangeList);
1957     InitializeListHead(&FdoExtension->MapTransferList);
1958     InitializeListHead(&FdoExtension->DeviceHandleList);
1959     InitializeListHead(&FdoExtension->IdleIrpList);
1960     InitializeListHead(&FdoExtension->BadRequestList);
1961     InitializeListHead(&FdoExtension->EndpointClosedList);
1962 
1963     DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1964 
1965     return Status;
1966 }
1967 
1968 VOID
1969 NTAPI
1970 USBPORT_Unload(IN PDRIVER_OBJECT DriverObject)
1971 {
1972     PUSBPORT_MINIPORT_INTERFACE MiniPortInterface;
1973 
1974     DPRINT1("USBPORT_Unload: FIXME!\n");
1975 
1976     MiniPortInterface = USBPORT_FindMiniPort(DriverObject);
1977 
1978     if (!MiniPortInterface)
1979     {
1980         DPRINT("USBPORT_Unload: CRITICAL ERROR!!! Not found MiniPortInterface\n");
1981         KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0);
1982     }
1983 
1984     DPRINT1("USBPORT_Unload: UNIMPLEMENTED. FIXME.\n");
1985     //MiniPortInterface->DriverUnload(DriverObject); // Call MiniPort _HCI_Unload
1986 }
1987 
1988 VOID
1989 NTAPI
1990 USBPORT_MiniportCompleteTransfer(IN PVOID MiniPortExtension,
1991                                  IN PVOID MiniPortEndpoint,
1992                                  IN PVOID TransferParameters,
1993                                  IN USBD_STATUS USBDStatus,
1994                                  IN ULONG TransferLength)
1995 {
1996     PUSBPORT_TRANSFER Transfer;
1997     PUSBPORT_TRANSFER ParentTransfer;
1998     PUSBPORT_TRANSFER SplitTransfer;
1999     PLIST_ENTRY SplitHead;
2000     PLIST_ENTRY Entry;
2001     KIRQL OldIrql;
2002 
2003     DPRINT_CORE("USBPORT_MiniportCompleteTransfer: USBDStatus - %x, TransferLength - %x\n",
2004                 USBDStatus,
2005                 TransferLength);
2006 
2007     Transfer = CONTAINING_RECORD(TransferParameters,
2008                                  USBPORT_TRANSFER,
2009                                  TransferParameters);
2010 
2011     Transfer->Flags |= TRANSFER_FLAG_COMPLETED;
2012     Transfer->CompletedTransferLen = TransferLength;
2013 
2014     if (((Transfer->Flags & TRANSFER_FLAG_SPLITED) == 0) ||
2015         TransferLength >= Transfer->TransferParameters.TransferBufferLength)
2016     {
2017         goto Exit;
2018     }
2019 
2020     ParentTransfer = Transfer->ParentTransfer;
2021 
2022     KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql);
2023 
2024     if (IsListEmpty(&ParentTransfer->SplitTransfersList))
2025     {
2026         goto Exit;
2027     }
2028 
2029     SplitHead = &ParentTransfer->SplitTransfersList;
2030     Entry = SplitHead->Flink;
2031 
2032     while (Entry && !IsListEmpty(SplitHead))
2033     {
2034         SplitTransfer = CONTAINING_RECORD(Entry,
2035                                           USBPORT_TRANSFER,
2036                                           SplitLink);
2037 
2038         if (!(SplitTransfer->Flags & TRANSFER_FLAG_SUBMITED))
2039         {
2040             DPRINT1("USBPORT_MiniportCompleteTransfer: SplitTransfer->Flags - %X\n",
2041                     SplitTransfer->Flags);
2042             //Add TRANSFER_FLAG_xxx
2043         }
2044 
2045         Entry = Entry->Flink;
2046     }
2047 
2048     KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
2049 
2050 Exit:
2051     USBPORT_QueueDoneTransfer(Transfer, USBDStatus);
2052 }
2053 
2054 VOID
2055 NTAPI
2056 USBPORT_AsyncTimerDpc(IN PRKDPC Dpc,
2057                       IN PVOID DeferredContext,
2058                       IN PVOID SystemArgument1,
2059                       IN PVOID SystemArgument2)
2060 {
2061     PDEVICE_OBJECT FdoDevice;
2062     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2063     PUSBPORT_ASYNC_CALLBACK_DATA AsyncCallbackData;
2064 
2065     DPRINT("USBPORT_AsyncTimerDpc: ...\n");
2066 
2067     AsyncCallbackData = DeferredContext;
2068     FdoDevice = AsyncCallbackData->FdoDevice;
2069     FdoExtension = FdoDevice->DeviceExtension;
2070 
2071     (*AsyncCallbackData->CallbackFunction)(FdoExtension->MiniPortExt,
2072                                            &AsyncCallbackData->CallbackContext);
2073 
2074     ExFreePoolWithTag(AsyncCallbackData, USB_PORT_TAG);
2075 }
2076 
2077 ULONG
2078 NTAPI
2079 USBPORT_RequestAsyncCallback(IN PVOID MiniPortExtension,
2080                              IN ULONG TimerValue,
2081                              IN PVOID Buffer,
2082                              IN SIZE_T Length,
2083                              IN ASYNC_TIMER_CALLBACK * Callback)
2084 {
2085     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2086     PDEVICE_OBJECT FdoDevice;
2087     PUSBPORT_ASYNC_CALLBACK_DATA AsyncCallbackData;
2088     LARGE_INTEGER DueTime = {{0, 0}};
2089 
2090     DPRINT("USBPORT_RequestAsyncCallback: ...\n");
2091 
2092     FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
2093                                                sizeof(USBPORT_DEVICE_EXTENSION));
2094 
2095     FdoDevice = FdoExtension->CommonExtension.SelfDevice;
2096 
2097     AsyncCallbackData = ExAllocatePoolWithTag(NonPagedPool,
2098                                               sizeof(USBPORT_ASYNC_CALLBACK_DATA) + Length,
2099                                               USB_PORT_TAG);
2100 
2101     if (!AsyncCallbackData)
2102     {
2103         DPRINT1("USBPORT_RequestAsyncCallback: Not allocated AsyncCallbackData!\n");
2104         return 0;
2105     }
2106 
2107     RtlZeroMemory(AsyncCallbackData,
2108                   sizeof(USBPORT_ASYNC_CALLBACK_DATA) + Length);
2109 
2110     if (Length)
2111     {
2112         RtlCopyMemory(&AsyncCallbackData->CallbackContext, Buffer, Length);
2113     }
2114 
2115     AsyncCallbackData->FdoDevice = FdoDevice;
2116     AsyncCallbackData->CallbackFunction = Callback;
2117 
2118     KeInitializeTimer(&AsyncCallbackData->AsyncTimer);
2119 
2120     KeInitializeDpc(&AsyncCallbackData->AsyncTimerDpc,
2121                     USBPORT_AsyncTimerDpc,
2122                     AsyncCallbackData);
2123 
2124     DueTime.QuadPart -= (KeQueryTimeIncrement() - 1) + 10000 * TimerValue;
2125 
2126     KeSetTimer(&AsyncCallbackData->AsyncTimer,
2127                DueTime,
2128                &AsyncCallbackData->AsyncTimerDpc);
2129 
2130     return 0;
2131 }
2132 
2133 PVOID
2134 NTAPI
2135 USBPORT_GetMappedVirtualAddress(IN ULONG PhysicalAddress,
2136                                 IN PVOID MiniPortExtension,
2137                                 IN PVOID MiniPortEndpoint)
2138 {
2139     PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer;
2140     PUSBPORT_ENDPOINT Endpoint;
2141     ULONG Offset;
2142     ULONG_PTR VirtualAddress;
2143 
2144     DPRINT_CORE("USBPORT_GetMappedVirtualAddress ...\n");
2145 
2146     Endpoint = (PUSBPORT_ENDPOINT)((ULONG_PTR)MiniPortEndpoint -
2147                                    sizeof(USBPORT_ENDPOINT));
2148 
2149     if (!Endpoint)
2150     {
2151         ASSERT(FALSE);
2152     }
2153 
2154     HeaderBuffer = Endpoint->HeaderBuffer;
2155 
2156     Offset = PhysicalAddress - HeaderBuffer->PhysicalAddress;
2157     VirtualAddress = HeaderBuffer->VirtualAddress + Offset;
2158 
2159     return (PVOID)VirtualAddress;
2160 }
2161 
2162 ULONG
2163 NTAPI
2164 USBPORT_InvalidateEndpoint(IN PVOID MiniPortExtension,
2165                            IN PVOID MiniPortEndpoint)
2166 {
2167     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2168     PDEVICE_OBJECT FdoDevice;
2169     PUSBPORT_ENDPOINT Endpoint;
2170 
2171     DPRINT_CORE("USBPORT_InvalidateEndpoint: ...\n");
2172 
2173     FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
2174                                                sizeof(USBPORT_DEVICE_EXTENSION));
2175 
2176     FdoDevice = FdoExtension->CommonExtension.SelfDevice;
2177 
2178     if (!MiniPortEndpoint)
2179     {
2180         USBPORT_InvalidateEndpointHandler(FdoDevice,
2181                                           NULL,
2182                                           INVALIDATE_ENDPOINT_ONLY);
2183         return 0;
2184     }
2185 
2186     Endpoint = (PUSBPORT_ENDPOINT)((ULONG_PTR)MiniPortEndpoint -
2187                                    sizeof(USBPORT_ENDPOINT));
2188 
2189     USBPORT_InvalidateEndpointHandler(FdoDevice,
2190                                       Endpoint,
2191                                       INVALIDATE_ENDPOINT_ONLY);
2192 
2193     return 0;
2194 }
2195 
2196 VOID
2197 NTAPI
2198 USBPORT_CompleteTransfer(IN PURB Urb,
2199                          IN USBD_STATUS TransferStatus)
2200 {
2201     struct _URB_CONTROL_TRANSFER *UrbTransfer;
2202     PUSBPORT_TRANSFER Transfer;
2203     NTSTATUS Status;
2204     PIRP Irp;
2205     KIRQL OldIrql;
2206     PRKEVENT Event;
2207     BOOLEAN WriteToDevice;
2208     BOOLEAN IsFlushSuccess;
2209     PMDL Mdl;
2210     ULONG_PTR CurrentVa;
2211     SIZE_T TransferLength;
2212     PUSBPORT_ENDPOINT Endpoint;
2213     PDEVICE_OBJECT FdoDevice;
2214     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2215     PDMA_OPERATIONS DmaOperations;
2216 
2217     DPRINT("USBPORT_CompleteTransfer: Urb - %p, TransferStatus - %X\n",
2218            Urb,
2219            TransferStatus);
2220 
2221     UrbTransfer = &Urb->UrbControlTransfer;
2222     Transfer = UrbTransfer->hca.Reserved8[0];
2223 
2224     Transfer->USBDStatus = TransferStatus;
2225     Status = USBPORT_USBDStatusToNtStatus(Urb, TransferStatus);
2226 
2227     UrbTransfer->TransferBufferLength = Transfer->CompletedTransferLen;
2228 
2229     if (Transfer->Flags & TRANSFER_FLAG_DMA_MAPPED)
2230     {
2231         Endpoint = Transfer->Endpoint;
2232         FdoDevice = Endpoint->FdoDevice;
2233         FdoExtension = FdoDevice->DeviceExtension;
2234         DmaOperations = FdoExtension->DmaAdapter->DmaOperations;
2235 
2236         WriteToDevice = Transfer->Direction == USBPORT_DMA_DIRECTION_TO_DEVICE;
2237         Mdl = UrbTransfer->TransferBufferMDL;
2238         CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
2239         TransferLength = UrbTransfer->TransferBufferLength;
2240 
2241         IsFlushSuccess = DmaOperations->FlushAdapterBuffers(FdoExtension->DmaAdapter,
2242                                                             Mdl,
2243                                                             Transfer->MapRegisterBase,
2244                                                             (PVOID)CurrentVa,
2245                                                             TransferLength,
2246                                                             WriteToDevice);
2247 
2248         if (!IsFlushSuccess)
2249         {
2250             DPRINT("USBPORT_CompleteTransfer: no FlushAdapterBuffers !!!\n");
2251             ASSERT(FALSE);
2252         }
2253 
2254         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2255 
2256         DmaOperations->FreeMapRegisters(FdoExtension->DmaAdapter,
2257                                         Transfer->MapRegisterBase,
2258                                         Transfer->NumberOfMapRegisters);
2259 
2260         KeLowerIrql(OldIrql);
2261     }
2262 
2263     if (Urb->UrbHeader.UsbdFlags & USBD_FLAG_ALLOCATED_MDL)
2264     {
2265         IoFreeMdl(Transfer->TransferBufferMDL);
2266         Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_MDL;
2267     }
2268 
2269     Urb->UrbControlTransfer.hca.Reserved8[0] = NULL;
2270     Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_TRANSFER;
2271 
2272     Irp = Transfer->Irp;
2273 
2274     if (Irp)
2275     {
2276         if (!NT_SUCCESS(Status))
2277         {
2278             //DbgBreakPoint();
2279             DPRINT1("USBPORT_CompleteTransfer: Irp - %p complete with Status - %lx\n",
2280                     Irp,
2281                     Status);
2282 
2283             USBPORT_DumpingURB(Urb);
2284         }
2285 
2286         Irp->IoStatus.Status = Status;
2287         Irp->IoStatus.Information = 0;
2288 
2289         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2290         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2291         KeLowerIrql(OldIrql);
2292     }
2293 
2294     Event = Transfer->Event;
2295 
2296     if (Event)
2297     {
2298         KeSetEvent(Event, EVENT_INCREMENT, FALSE);
2299     }
2300 
2301     ExFreePoolWithTag(Transfer, USB_PORT_TAG);
2302 
2303     DPRINT_CORE("USBPORT_CompleteTransfer: exit\n");
2304 }
2305 
2306 IO_ALLOCATION_ACTION
2307 NTAPI
2308 USBPORT_MapTransfer(IN PDEVICE_OBJECT FdoDevice,
2309                     IN PIRP Irp,
2310                     IN PVOID MapRegisterBase,
2311                     IN PVOID Context)
2312 {
2313     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2314     PDMA_ADAPTER DmaAdapter;
2315     PUSBPORT_TRANSFER Transfer;
2316     PURB Urb;
2317     PUSBPORT_ENDPOINT Endpoint;
2318     PMDL Mdl;
2319     ULONG_PTR CurrentVa;
2320     PUSBPORT_SCATTER_GATHER_LIST sgList;
2321     SIZE_T CurrentLength;
2322     ULONG ix;
2323     BOOLEAN WriteToDevice;
2324     PHYSICAL_ADDRESS PhAddr = {{0, 0}};
2325     PHYSICAL_ADDRESS PhAddress = {{0, 0}};
2326     ULONG TransferLength;
2327     SIZE_T SgCurrentLength;
2328     SIZE_T ElementLength;
2329     PUSBPORT_DEVICE_HANDLE DeviceHandle;
2330     PDMA_OPERATIONS DmaOperations;
2331     USBD_STATUS USBDStatus;
2332     LIST_ENTRY List;
2333     PUSBPORT_TRANSFER transfer;
2334 
2335     DPRINT_CORE("USBPORT_MapTransfer: ...\n");
2336 
2337     FdoExtension = FdoDevice->DeviceExtension;
2338     DmaAdapter = FdoExtension->DmaAdapter;
2339     DmaOperations = DmaAdapter->DmaOperations;
2340 
2341     Transfer = Context;
2342 
2343     Urb = Transfer->Urb;
2344     Endpoint = Transfer->Endpoint;
2345     TransferLength = Transfer->TransferParameters.TransferBufferLength;
2346 
2347     Mdl = Urb->UrbControlTransfer.TransferBufferMDL;
2348     CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
2349 
2350     sgList = &Transfer->SgList;
2351 
2352     sgList->Flags = 0;
2353     sgList->CurrentVa = CurrentVa;
2354     sgList->MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl,
2355                                                           NormalPagePriority);
2356     Transfer->MapRegisterBase = MapRegisterBase;
2357 
2358     ix = 0;
2359     CurrentLength = 0;
2360 
2361     do
2362     {
2363         WriteToDevice = Transfer->Direction == USBPORT_DMA_DIRECTION_TO_DEVICE;
2364         ASSERT(Transfer->Direction != 0);
2365 
2366         PhAddress = DmaOperations->MapTransfer(DmaAdapter,
2367                                                Mdl,
2368                                                MapRegisterBase,
2369                                                (PVOID)CurrentVa,
2370                                                &TransferLength,
2371                                                WriteToDevice);
2372 
2373         DPRINT_CORE("USBPORT_MapTransfer: PhAddress.LowPart - %p, PhAddress.HighPart - %x, TransferLength - %x\n",
2374                PhAddress.LowPart,
2375                PhAddress.HighPart,
2376                TransferLength);
2377 
2378         PhAddress.HighPart = 0;
2379         SgCurrentLength = TransferLength;
2380 
2381         do
2382         {
2383             ElementLength = PAGE_SIZE - (PhAddress.LowPart & (PAGE_SIZE - 1));
2384 
2385             if (ElementLength > SgCurrentLength)
2386                 ElementLength = SgCurrentLength;
2387 
2388             DPRINT_CORE("USBPORT_MapTransfer: PhAddress.LowPart - %p, HighPart - %x, ElementLength - %x\n",
2389                    PhAddress.LowPart,
2390                    PhAddress.HighPart,
2391                    ElementLength);
2392 
2393             sgList->SgElement[ix].SgPhysicalAddress = PhAddress;
2394             sgList->SgElement[ix].SgTransferLength = ElementLength;
2395             sgList->SgElement[ix].SgOffset = CurrentLength +
2396                                              (TransferLength - SgCurrentLength);
2397 
2398             PhAddress.LowPart += ElementLength;
2399             SgCurrentLength -= ElementLength;
2400 
2401             ++ix;
2402         }
2403         while (SgCurrentLength);
2404 
2405         if (PhAddr.QuadPart == PhAddress.QuadPart)
2406         {
2407             DPRINT1("USBPORT_MapTransfer: PhAddr == PhAddress\n");
2408             ASSERT(FALSE);
2409         }
2410 
2411         PhAddr = PhAddress;
2412 
2413         CurrentLength += TransferLength;
2414         CurrentVa += TransferLength;
2415 
2416         TransferLength = Transfer->TransferParameters.TransferBufferLength -
2417                          CurrentLength;
2418     }
2419     while (CurrentLength != Transfer->TransferParameters.TransferBufferLength);
2420 
2421     sgList->SgElementCount = ix;
2422 
2423     if (Endpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed)
2424     {
2425         Transfer->Flags |= TRANSFER_FLAG_HIGH_SPEED;
2426     }
2427 
2428     Transfer->Flags |= TRANSFER_FLAG_DMA_MAPPED;
2429 
2430     if ((Transfer->Flags & TRANSFER_FLAG_ISO) == 0)
2431     {
2432         KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
2433                           &Endpoint->EndpointOldIrql);
2434 
2435         USBPORT_SplitTransfer(FdoDevice, Endpoint, Transfer, &List);
2436 
2437         while (!IsListEmpty(&List))
2438         {
2439             transfer = CONTAINING_RECORD(List.Flink,
2440                                          USBPORT_TRANSFER,
2441                                          TransferLink);
2442 
2443             RemoveHeadList(&List);
2444             InsertTailList(&Endpoint->TransferList, &transfer->TransferLink);
2445         }
2446 
2447         KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
2448                           Endpoint->EndpointOldIrql);
2449     }
2450     else
2451     {
2452         USBDStatus = USBPORT_InitializeIsoTransfer(FdoDevice,
2453                                                    &Urb->UrbIsochronousTransfer,
2454                                                    Transfer);
2455 
2456         if (USBDStatus != USBD_STATUS_SUCCESS)
2457         {
2458             KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
2459                               &Endpoint->EndpointOldIrql);
2460 
2461             USBPORT_QueueDoneTransfer(Transfer, USBDStatus);
2462 
2463             KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
2464                               Endpoint->EndpointOldIrql);
2465         }
2466     }
2467 
2468     DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle;
2469     InterlockedDecrement(&DeviceHandle->DeviceHandleLock);
2470 
2471     if (USBPORT_EndpointWorker(Endpoint, 0))
2472     {
2473         USBPORT_InvalidateEndpointHandler(FdoDevice,
2474                                           Endpoint,
2475                                           INVALIDATE_ENDPOINT_WORKER_THREAD);
2476     }
2477 
2478     return DeallocateObjectKeepRegisters;
2479 }
2480 
2481 VOID
2482 NTAPI
2483 USBPORT_FlushMapTransfers(IN PDEVICE_OBJECT FdoDevice)
2484 {
2485     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2486     PLIST_ENTRY MapTransferList;
2487     PUSBPORT_TRANSFER Transfer;
2488     ULONG NumMapRegisters;
2489     PMDL Mdl;
2490     SIZE_T TransferBufferLength;
2491     ULONG_PTR VirtualAddr;
2492     KIRQL OldIrql;
2493     NTSTATUS Status;
2494     PDMA_OPERATIONS DmaOperations;
2495 
2496     DPRINT_CORE("USBPORT_FlushMapTransfers: ...\n");
2497 
2498     FdoExtension = FdoDevice->DeviceExtension;
2499     DmaOperations = FdoExtension->DmaAdapter->DmaOperations;
2500 
2501     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2502 
2503     while (TRUE)
2504     {
2505         MapTransferList = &FdoExtension->MapTransferList;
2506 
2507         if (IsListEmpty(&FdoExtension->MapTransferList))
2508         {
2509             KeLowerIrql(OldIrql);
2510             return;
2511         }
2512 
2513         Transfer = CONTAINING_RECORD(MapTransferList->Flink,
2514                                      USBPORT_TRANSFER,
2515                                      TransferLink);
2516 
2517         RemoveHeadList(MapTransferList);
2518 
2519         Mdl = Transfer->Urb->UrbControlTransfer.TransferBufferMDL;
2520         TransferBufferLength = Transfer->TransferParameters.TransferBufferLength;
2521         VirtualAddr = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
2522 
2523         NumMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr,
2524                                                          TransferBufferLength);
2525 
2526         Transfer->NumberOfMapRegisters = NumMapRegisters;
2527 
2528         Status = DmaOperations->AllocateAdapterChannel(FdoExtension->DmaAdapter,
2529                                                        FdoDevice,
2530                                                        NumMapRegisters,
2531                                                        USBPORT_MapTransfer,
2532                                                        Transfer);
2533 
2534         if (!NT_SUCCESS(Status))
2535             ASSERT(FALSE);
2536     }
2537 
2538     KeLowerIrql(OldIrql);
2539 }
2540 
2541 USBD_STATUS
2542 NTAPI
2543 USBPORT_AllocateTransfer(IN PDEVICE_OBJECT FdoDevice,
2544                          IN PURB Urb,
2545                          IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
2546                          IN PIRP Irp,
2547                          IN PRKEVENT Event)
2548 {
2549     PUSBPORT_DEVICE_EXTENSION FdoExtension;
2550     SIZE_T TransferLength;
2551     PMDL Mdl;
2552     ULONG_PTR VirtualAddr;
2553     ULONG PagesNeed = 0;
2554     SIZE_T PortTransferLength;
2555     SIZE_T FullTransferLength;
2556     PUSBPORT_TRANSFER Transfer;
2557     PUSBPORT_PIPE_HANDLE PipeHandle;
2558     USBD_STATUS USBDStatus;
2559     SIZE_T IsoBlockLen = 0;
2560 
2561     DPRINT_CORE("USBPORT_AllocateTransfer: FdoDevice - %p, Urb - %p, DeviceHandle - %p, Irp - %p, Event - %p\n",
2562            FdoDevice,
2563            Urb,
2564            DeviceHandle,
2565            Irp,
2566            Event);
2567 
2568     FdoExtension = FdoDevice->DeviceExtension;
2569 
2570     TransferLength = Urb->UrbControlTransfer.TransferBufferLength;
2571     PipeHandle = Urb->UrbControlTransfer.PipeHandle;
2572 
2573     if (TransferLength)
2574     {
2575         Mdl = Urb->UrbControlTransfer.TransferBufferMDL;
2576         VirtualAddr = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
2577 
2578         PagesNeed = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr,
2579                                                    TransferLength);
2580         if (PagesNeed > 0)
2581         {
2582             PagesNeed--;
2583         }
2584     }
2585 
2586     if (Urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
2587     {
2588         DPRINT1("USBPORT_AllocateTransfer: ISOCH_TRANSFER UNIMPLEMENTED. FIXME\n");
2589 
2590         //IsoBlockLen = sizeof(USBPORT_ISO_BLOCK) +
2591         //              Urb->UrbIsochronousTransfer.NumberOfPackets *
2592         //              sizeof(USBPORT_ISO_BLOCK_PACKET);
2593     }
2594 
2595     PortTransferLength = sizeof(USBPORT_TRANSFER) +
2596                          PagesNeed * sizeof(USBPORT_SCATTER_GATHER_ELEMENT) +
2597                          IsoBlockLen;
2598 
2599     FullTransferLength = PortTransferLength +
2600                          FdoExtension->MiniPortInterface->Packet.MiniPortTransferSize;
2601 
2602     Transfer = ExAllocatePoolWithTag(NonPagedPool,
2603                                      FullTransferLength,
2604                                      USB_PORT_TAG);
2605 
2606     if (!Transfer)
2607     {
2608         DPRINT1("USBPORT_AllocateTransfer: Transfer not allocated!\n");
2609         return USBD_STATUS_INSUFFICIENT_RESOURCES;
2610     }
2611 
2612     RtlZeroMemory(Transfer, FullTransferLength);
2613 
2614     Transfer->Irp = Irp;
2615     Transfer->Urb = Urb;
2616     Transfer->Endpoint = PipeHandle->Endpoint;
2617     Transfer->Event = Event;
2618     Transfer->PortTransferLength = PortTransferLength;
2619     Transfer->FullTransferLength = FullTransferLength;
2620     Transfer->IsoBlockPtr = NULL;
2621     Transfer->Period = 0;
2622     Transfer->ParentTransfer = Transfer;
2623 
2624     if (IsoBlockLen)
2625     {
2626         Transfer->IsoBlockPtr = (PVOID)((ULONG_PTR)Transfer +
2627                                  PortTransferLength - IsoBlockLen);
2628 
2629         Transfer->Period = PipeHandle->Endpoint->EndpointProperties.Period;
2630         Transfer->Flags |= TRANSFER_FLAG_ISO;
2631     }
2632 
2633     Transfer->MiniportTransfer = (PVOID)((ULONG_PTR)Transfer +
2634                                                     PortTransferLength);
2635 
2636     KeInitializeSpinLock(&Transfer->TransferSpinLock);
2637 
2638     Urb->UrbControlTransfer.hca.Reserved8[0] = Transfer;
2639     Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_TRANSFER;
2640 
2641     USBDStatus = USBD_STATUS_SUCCESS;
2642 
2643     DPRINT_CORE("USBPORT_AllocateTransfer: return USBDStatus - %x\n",
2644                 USBDStatus);
2645 
2646     return USBDStatus;
2647 }
2648 
2649 NTSTATUS
2650 NTAPI
2651 USBPORT_Dispatch(IN PDEVICE_OBJECT DeviceObject,
2652                  IN PIRP Irp)
2653 {
2654     PUSBPORT_COMMON_DEVICE_EXTENSION DeviceExtension;
2655     PIO_STACK_LOCATION IoStack;
2656     NTSTATUS Status = STATUS_SUCCESS;
2657 
2658     DeviceExtension = DeviceObject->DeviceExtension;
2659     IoStack = IoGetCurrentIrpStackLocation(Irp);
2660 
2661     if (DeviceExtension->PnpStateFlags & USBPORT_PNP_STATE_FAILED)
2662     {
2663         DPRINT1("USBPORT_Dispatch: USBPORT_PNP_STATE_FAILED\n");
2664         DbgBreakPoint();
2665     }
2666 
2667     switch (IoStack->MajorFunction)
2668     {
2669         case IRP_MJ_DEVICE_CONTROL:
2670             if (DeviceExtension->IsPDO)
2671             {
2672                 DPRINT("USBPORT_Dispatch: PDO IRP_MJ_DEVICE_CONTROL. Major - %d, Minor - %d\n",
2673                        IoStack->MajorFunction,
2674                        IoStack->MinorFunction);
2675 
2676                 Status = USBPORT_PdoDeviceControl(DeviceObject, Irp);
2677             }
2678             else
2679             {
2680                 DPRINT("USBPORT_Dispatch: FDO IRP_MJ_DEVICE_CONTROL. Major - %d, Minor - %d\n",
2681                        IoStack->MajorFunction,
2682                        IoStack->MinorFunction);
2683 
2684                 Status = USBPORT_FdoDeviceControl(DeviceObject, Irp);
2685             }
2686 
2687             break;
2688 
2689         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
2690             if (DeviceExtension->IsPDO)
2691             {
2692                 DPRINT("USBPORT_Dispatch: PDO IRP_MJ_INTERNAL_DEVICE_CONTROL. Major - %d, Minor - %d\n",
2693                        IoStack->MajorFunction,
2694                        IoStack->MinorFunction);
2695 
2696                 Status = USBPORT_PdoInternalDeviceControl(DeviceObject, Irp);
2697             }
2698             else
2699             {
2700                 DPRINT("USBPORT_Dispatch: FDO IRP_MJ_INTERNAL_DEVICE_CONTROL. Major - %d, Minor - %d\n",
2701                        IoStack->MajorFunction,
2702                        IoStack->MinorFunction);
2703 
2704                 Status = USBPORT_FdoInternalDeviceControl(DeviceObject, Irp);
2705             }
2706 
2707             break;
2708 
2709         case IRP_MJ_POWER:
2710             if (DeviceExtension->IsPDO)
2711             {
2712                 DPRINT("USBPORT_Dispatch: PDO IRP_MJ_POWER. Major - %d, Minor - %d\n",
2713                        IoStack->MajorFunction,
2714                        IoStack->MinorFunction);
2715 
2716                 Status = USBPORT_PdoPower(DeviceObject, Irp);
2717             }
2718             else
2719             {
2720                 DPRINT("USBPORT_Dispatch: FDO IRP_MJ_POWER. Major - %d, Minor - %d\n",
2721                        IoStack->MajorFunction,
2722                        IoStack->MinorFunction);
2723 
2724                 Status = USBPORT_FdoPower(DeviceObject, Irp);
2725             }
2726 
2727             break;
2728 
2729         case IRP_MJ_SYSTEM_CONTROL:
2730             if (DeviceExtension->IsPDO)
2731             {
2732                 DPRINT("USBPORT_Dispatch: PDO IRP_MJ_SYSTEM_CONTROL. Major - %d, Minor - %d\n",
2733                        IoStack->MajorFunction,
2734                        IoStack->MinorFunction);
2735 
2736                 Status = Irp->IoStatus.Status;
2737                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2738             }
2739             else
2740             {
2741                 DPRINT("USBPORT_Dispatch: FDO IRP_MJ_SYSTEM_CONTROL. Major - %d, Minor - %d\n",
2742                        IoStack->MajorFunction,
2743                        IoStack->MinorFunction);
2744 
2745                 IoSkipCurrentIrpStackLocation(Irp);
2746                 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
2747             }
2748 
2749             break;
2750 
2751         case IRP_MJ_PNP:
2752             if (DeviceExtension->IsPDO)
2753             {
2754                 DPRINT("USBPORT_Dispatch: PDO IRP_MJ_PNP. Major - %d, Minor - %d\n",
2755                        IoStack->MajorFunction,
2756                        IoStack->MinorFunction);
2757 
2758                 Status = USBPORT_PdoPnP(DeviceObject, Irp);
2759             }
2760             else
2761             {
2762                 DPRINT("USBPORT_Dispatch: FDO IRP_MJ_PNP. Major - %d, Minor - %d\n",
2763                        IoStack->MajorFunction,
2764                        IoStack->MinorFunction);
2765 
2766                 Status = USBPORT_FdoPnP(DeviceObject, Irp);
2767             }
2768 
2769             break;
2770 
2771         case IRP_MJ_CREATE:
2772         case IRP_MJ_CLOSE:
2773             DPRINT("USBPORT_Dispatch: IRP_MJ_CREATE | IRP_MJ_CLOSE\n");
2774             Irp->IoStatus.Status = Status;
2775             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2776             break;
2777 
2778         default:
2779             if (DeviceExtension->IsPDO)
2780             {
2781                 DPRINT("USBPORT_Dispatch: PDO unhandled IRP_MJ_???. Major - %d, Minor - %d\n",
2782                        IoStack->MajorFunction,
2783                        IoStack->MinorFunction);
2784             }
2785             else
2786             {
2787                 DPRINT("USBPORT_Dispatch: FDO unhandled IRP_MJ_???. Major - %d, Minor - %d\n",
2788                        IoStack->MajorFunction,
2789                        IoStack->MinorFunction);
2790             }
2791 
2792             Status = STATUS_INVALID_DEVICE_REQUEST;
2793             Irp->IoStatus.Status = Status;
2794             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2795             break;
2796     }
2797 
2798     DPRINT("USBPORT_Dispatch: Status - %x\n", Status);
2799     return Status;
2800 }
2801 
2802 ULONG
2803 NTAPI
2804 USBPORT_GetHciMn(VOID)
2805 {
2806     return USBPORT_HCI_MN;
2807 }
2808 
2809 NTSTATUS
2810 NTAPI
2811 USBPORT_RegisterUSBPortDriver(IN PDRIVER_OBJECT DriverObject,
2812                               IN ULONG Version,
2813                               IN PUSBPORT_REGISTRATION_PACKET RegPacket)
2814 {
2815     PUSBPORT_MINIPORT_INTERFACE MiniPortInterface;
2816 
2817     DPRINT("USBPORT_RegisterUSBPortDriver: DriverObject - %p, Version - %p, RegPacket - %p\n",
2818            DriverObject,
2819            Version,
2820            RegPacket);
2821 
2822     DPRINT("USBPORT_RegisterUSBPortDriver: sizeof(USBPORT_MINIPORT_INTERFACE) - %x\n",
2823            sizeof(USBPORT_MINIPORT_INTERFACE));
2824 
2825     DPRINT("USBPORT_RegisterUSBPortDriver: sizeof(USBPORT_DEVICE_EXTENSION)   - %x\n",
2826            sizeof(USBPORT_DEVICE_EXTENSION));
2827 
2828     if (Version < USB10_MINIPORT_INTERFACE_VERSION)
2829     {
2830         return STATUS_UNSUCCESSFUL;
2831     }
2832 
2833     if (!USBPORT_Initialized)
2834     {
2835         InitializeListHead(&USBPORT_MiniPortDrivers);
2836         InitializeListHead(&USBPORT_USB1FdoList);
2837         InitializeListHead(&USBPORT_USB2FdoList);
2838 
2839         KeInitializeSpinLock(&USBPORT_SpinLock);
2840         USBPORT_Initialized = TRUE;
2841     }
2842 
2843     MiniPortInterface = ExAllocatePoolWithTag(NonPagedPool,
2844                                               sizeof(USBPORT_MINIPORT_INTERFACE),
2845                                               USB_PORT_TAG);
2846     if (!MiniPortInterface)
2847     {
2848         return STATUS_INSUFFICIENT_RESOURCES;
2849     }
2850 
2851     RtlZeroMemory(MiniPortInterface, sizeof(USBPORT_MINIPORT_INTERFACE));
2852 
2853     MiniPortInterface->DriverObject = DriverObject;
2854     MiniPortInterface->DriverUnload = DriverObject->DriverUnload;
2855     MiniPortInterface->Version = Version;
2856 
2857     ExInterlockedInsertTailList(&USBPORT_MiniPortDrivers,
2858                                 &MiniPortInterface->DriverLink,
2859                                 &USBPORT_SpinLock);
2860 
2861     DriverObject->DriverExtension->AddDevice = USBPORT_AddDevice;
2862     DriverObject->DriverUnload = USBPORT_Unload;
2863 
2864     DriverObject->MajorFunction[IRP_MJ_CREATE] = USBPORT_Dispatch;
2865     DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBPORT_Dispatch;
2866     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBPORT_Dispatch;
2867     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBPORT_Dispatch;
2868     DriverObject->MajorFunction[IRP_MJ_PNP] = USBPORT_Dispatch;
2869     DriverObject->MajorFunction[IRP_MJ_POWER] = USBPORT_Dispatch;
2870     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBPORT_Dispatch;
2871 
2872     RegPacket->UsbPortDbgPrint = USBPORT_DbgPrint;
2873     RegPacket->UsbPortTestDebugBreak = USBPORT_TestDebugBreak;
2874     RegPacket->UsbPortAssertFailure = USBPORT_AssertFailure;
2875     RegPacket->UsbPortGetMiniportRegistryKeyValue = USBPORT_GetMiniportRegistryKeyValue;
2876     RegPacket->UsbPortInvalidateRootHub = USBPORT_InvalidateRootHub;
2877     RegPacket->UsbPortInvalidateEndpoint = USBPORT_InvalidateEndpoint;
2878     RegPacket->UsbPortCompleteTransfer = USBPORT_MiniportCompleteTransfer;
2879     RegPacket->UsbPortCompleteIsoTransfer = USBPORT_CompleteIsoTransfer;
2880     RegPacket->UsbPortLogEntry = USBPORT_LogEntry;
2881     RegPacket->UsbPortGetMappedVirtualAddress = USBPORT_GetMappedVirtualAddress;
2882     RegPacket->UsbPortRequestAsyncCallback = USBPORT_RequestAsyncCallback;
2883     RegPacket->UsbPortReadWriteConfigSpace = USBPORT_ReadWriteConfigSpace;
2884     RegPacket->UsbPortWait = USBPORT_Wait;
2885     RegPacket->UsbPortInvalidateController = USBPORT_InvalidateController;
2886     RegPacket->UsbPortBugCheck = USBPORT_BugCheck;
2887     RegPacket->UsbPortNotifyDoubleBuffer = USBPORT_NotifyDoubleBuffer;
2888 
2889     RtlCopyMemory(&MiniPortInterface->Packet,
2890                   RegPacket,
2891                   sizeof(USBPORT_REGISTRATION_PACKET));
2892 
2893     return STATUS_SUCCESS;
2894 }
2895 
2896 NTSTATUS
2897 NTAPI
2898 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2899             IN PUNICODE_STRING RegistryPath)
2900 {
2901     return STATUS_SUCCESS;
2902 }
2903