xref: /reactos/drivers/usb/usbhub/pnp.c (revision 53221834)
1 /*
2  * PROJECT:     ReactOS USB Hub Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBHub plug and play functions
5  * COPYRIGHT:   Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbhub.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #define NDEBUG_USBHUB_PNP
14 #define NDEBUG_USBHUB_ENUM
15 #include "dbg_uhub.h"
16 
17 NTSTATUS
18 NTAPI
19 USBH_IrpCompletion(IN PDEVICE_OBJECT DeviceObject,
20                    IN PIRP Irp,
21                    IN PVOID Context)
22 {
23     PRKEVENT Event;
24 
25     DPRINT("USBH_IrpCompletion: Irp - %p\n", Irp);
26 
27     Event = Context;
28     KeSetEvent(Event, EVENT_INCREMENT, FALSE);
29     return STATUS_MORE_PROCESSING_REQUIRED;
30 }
31 
32 NTSTATUS
33 NTAPI
34 USBH_HubPnPIrpComplete(IN PDEVICE_OBJECT DeviceObject,
35                        IN PIRP Irp,
36                        IN PVOID Context)
37 {
38     PUSBHUB_FDO_EXTENSION HubExtension;
39 
40     DPRINT("USBH_HubPnPIrpComplete: Irp - %p\n", Irp);
41 
42      HubExtension = Context;
43 
44     if (!NT_SUCCESS(Irp->IoStatus.Status))
45     {
46         DPRINT1("USBH_HubPnPIrpComplete: Irp failed - %lX\n", Irp->IoStatus.Status);
47         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
48     }
49 
50     Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED;
51 
52     KeSetEvent(&HubExtension->LowerDeviceEvent, EVENT_INCREMENT, FALSE);
53 
54     return STATUS_MORE_PROCESSING_REQUIRED;
55 }
56 
57 NTSTATUS
58 NTAPI
59 USBH_QueryCapsComplete(IN PDEVICE_OBJECT DeviceObject,
60                        IN PIRP Irp,
61                        IN PVOID Context)
62 {
63     PIO_STACK_LOCATION IoStack;
64     PDEVICE_CAPABILITIES Capabilities;
65 
66     DPRINT("USBH_QueryCapsComplete: ... \n");
67 
68     ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
69 
70     if (Irp->PendingReturned)
71     {
72         IoMarkIrpPending(Irp);
73     }
74 
75     IoStack= IoGetCurrentIrpStackLocation(Irp);
76     Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
77 
78     Capabilities->SurpriseRemovalOK = 1;
79 
80     return STATUS_CONTINUE_COMPLETION;
81 }
82 
83 NTSTATUS
84 NTAPI
85 USBHUB_GetBusInterface(IN PDEVICE_OBJECT DeviceObject,
86                        OUT PUSB_BUS_INTERFACE_HUB_V5 BusInterface)
87 {
88     PIRP Irp;
89     NTSTATUS Status;
90     PIO_STACK_LOCATION IoStack;
91     KEVENT Event;
92 
93     DPRINT("USBHUB_GetBusInterface: ... \n");
94 
95     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
96 
97     if (!Irp)
98     {
99         DPRINT1("USBHUB_GetBusInterface: IoAllocateIrp() failed\n");
100         return STATUS_INSUFFICIENT_RESOURCES;
101     }
102 
103     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
104 
105     KeInitializeEvent(&Event, NotificationEvent, FALSE);
106 
107     IoSetCompletionRoutine(Irp,
108                            USBH_IrpCompletion,
109                            &Event,
110                            TRUE,
111                            TRUE,
112                            TRUE);
113 
114     IoStack = IoGetNextIrpStackLocation(Irp);
115 
116     IoStack->MajorFunction = IRP_MJ_PNP;
117     IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
118 
119     IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_HUB_GUID;
120     IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_HUB_V5);
121     IoStack->Parameters.QueryInterface.Version = USB_BUSIF_HUB_VERSION_5;
122     IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
123     IoStack->Parameters.QueryInterface.InterfaceSpecificData = DeviceObject;
124 
125     Status = IoCallDriver(DeviceObject, Irp);
126 
127     if (Status == STATUS_PENDING)
128     {
129         KeWaitForSingleObject(&Event,
130                               Suspended,
131                               KernelMode,
132                               FALSE,
133                               NULL);
134 
135         Status = Irp->IoStatus.Status;
136     }
137 
138     IoFreeIrp(Irp);
139 
140     return Status;
141 }
142 
143 NTSTATUS
144 NTAPI
145 USBHUB_GetBusInterfaceUSBDI(IN PDEVICE_OBJECT DeviceObject,
146                             OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterfaceUSBDI)
147 {
148     PIRP Irp;
149     NTSTATUS Status;
150     PIO_STACK_LOCATION IoStack;
151     KEVENT Event;
152 
153     DPRINT("USBHUB_GetBusInterfaceUSBDI: ... \n");
154 
155     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
156 
157     if (!Irp)
158     {
159         DPRINT1("USBHUB_GetBusInterfaceUSBDI: IoAllocateIrp() failed\n");
160         return STATUS_INSUFFICIENT_RESOURCES;
161     }
162 
163     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
164 
165     KeInitializeEvent(&Event, NotificationEvent, FALSE);
166 
167     IoSetCompletionRoutine(Irp,
168                            USBH_IrpCompletion,
169                            &Event,
170                            TRUE,
171                            TRUE,
172                            TRUE);
173 
174     IoStack = IoGetNextIrpStackLocation(Irp);
175 
176     IoStack->MajorFunction = IRP_MJ_PNP;
177     IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
178 
179     IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID;
180     IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V2);
181     IoStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_2;
182     IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterfaceUSBDI;
183     IoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
184 
185     Status = IoCallDriver(DeviceObject, Irp);
186 
187     if (Status == STATUS_PENDING)
188     {
189         KeWaitForSingleObject(&Event,
190                               Suspended,
191                               KernelMode,
192                               FALSE,
193                               NULL);
194 
195         Status = Irp->IoStatus.Status;
196     }
197 
198     IoFreeIrp(Irp);
199 
200     return Status;
201 }
202 
203 VOID
204 NTAPI
205 USBH_QueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
206                        IN PDEVICE_CAPABILITIES DeviceCapabilities)
207 {
208     PIRP Irp;
209     PIO_STACK_LOCATION IoStack;
210     KEVENT Event;
211 
212     DPRINT("USBH_QueryCapabilities: ... \n");
213 
214     RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
215 
216     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
217 
218     if (!Irp)
219     {
220         DPRINT1("USBH_QueryCapabilities: IoAllocateIrp() failed\n");
221         return;
222     }
223 
224     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
225 
226     KeInitializeEvent(&Event, NotificationEvent, FALSE);
227 
228     IoSetCompletionRoutine(Irp,
229                            USBH_IrpCompletion,
230                            &Event,
231                            TRUE,
232                            TRUE,
233                            TRUE);
234 
235     IoStack = IoGetNextIrpStackLocation(Irp);
236 
237     IoStack->MajorFunction = IRP_MJ_PNP;
238     IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
239 
240     IoStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
241     IoStack->Parameters.DeviceCapabilities.Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
242     IoStack->Parameters.DeviceCapabilities.Capabilities->Version = 1;
243     IoStack->Parameters.DeviceCapabilities.Capabilities->Address = MAXULONG;
244     IoStack->Parameters.DeviceCapabilities.Capabilities->UINumber = MAXULONG;
245 
246     if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
247     {
248         KeWaitForSingleObject(&Event,
249                               Suspended,
250                               KernelMode,
251                               FALSE,
252                               NULL);
253     }
254 
255     IoFreeIrp(Irp);
256 }
257 
258 NTSTATUS
259 NTAPI
260 USBH_OpenConfiguration(IN PUSBHUB_FDO_EXTENSION HubExtension)
261 {
262     PUSB_INTERFACE_DESCRIPTOR Pid;
263     PURB Urb;
264     NTSTATUS Status;
265     USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
266 
267     DPRINT("USBH_OpenConfiguration ... \n");
268 
269     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB &&
270         HubExtension->LowerPDO != HubExtension->RootHubPdo)
271     {
272         Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
273                                                   HubExtension->HubConfigDescriptor,
274                                                   -1,
275                                                   -1,
276                                                   USB_DEVICE_CLASS_HUB,
277                                                   -1,
278                                                   2);
279 
280         if (Pid)
281         {
282             HubExtension->HubFlags |= USBHUB_FDO_FLAG_MULTIPLE_TTS;
283         }
284         else
285         {
286             Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
287                                                       HubExtension->HubConfigDescriptor,
288                                                       -1,
289                                                       -1,
290                                                       USB_DEVICE_CLASS_HUB,
291                                                       -1,
292                                                       1);
293 
294             if (Pid)
295             {
296                 goto Next;
297             }
298 
299             Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
300                                                       HubExtension->HubConfigDescriptor,
301                                                       -1,
302                                                       -1,
303                                                       USB_DEVICE_CLASS_HUB,
304                                                       -1,
305                                                       0);
306         }
307     }
308     else
309     {
310         Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
311                                                   HubExtension->HubConfigDescriptor,
312                                                   -1,
313                                                   -1,
314                                                   USB_DEVICE_CLASS_HUB,
315                                                   -1,
316                                                   -1);
317     }
318 
319     if (!Pid)
320     {
321         return STATUS_UNSUCCESSFUL;
322     }
323 
324   Next:
325 
326     if (Pid->bInterfaceClass != USB_DEVICE_CLASS_HUB)
327     {
328         return STATUS_UNSUCCESSFUL;
329     }
330 
331     InterfaceList[0].InterfaceDescriptor = Pid;
332 
333     Urb = USBD_CreateConfigurationRequestEx(HubExtension->HubConfigDescriptor,
334                                             InterfaceList);
335 
336     if (!Urb)
337     {
338         return STATUS_INSUFFICIENT_RESOURCES;
339     }
340 
341     Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, Urb);
342 
343     if (NT_SUCCESS(Status))
344     {
345         RtlCopyMemory(&HubExtension->PipeInfo,
346                       InterfaceList[0].Interface->Pipes,
347                       sizeof(USBD_PIPE_INFORMATION));
348 
349         HubExtension->ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
350     }
351 
352     ExFreePool(Urb);
353 
354     return Status;
355 }
356 
357 NTSTATUS
358 NTAPI
359 USBD_Initialize20Hub(IN PUSBHUB_FDO_EXTENSION HubExtension)
360 {
361     PUSB_BUSIFFN_INITIALIZE_20HUB Initialize20Hub;
362     ULONG TtCount;
363     PUSB_DEVICE_HANDLE DeviceHandle;
364 
365     DPRINT("USBD_InitUsb2Hub ... \n");
366 
367     Initialize20Hub = HubExtension->BusInterface.Initialize20Hub;
368 
369     if (!Initialize20Hub)
370     {
371         return STATUS_NOT_IMPLEMENTED;
372     }
373 
374     TtCount = 1;
375 
376     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_MULTIPLE_TTS)
377     {
378         TtCount = HubExtension->HubDescriptor->bNumberOfPorts;
379     }
380 
381     DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
382 
383     return Initialize20Hub(HubExtension->BusInterface.BusContext,
384                            DeviceHandle,
385                            TtCount);
386 }
387 
388 NTSTATUS
389 NTAPI
390 USBH_AbortInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
391 {
392     struct _URB_PIPE_REQUEST * Urb;
393     NTSTATUS Status;
394 
395     DPRINT("USBH_AbortInterruptPipe: HubExtension - %p\n", HubExtension);
396 
397     Urb = ExAllocatePoolWithTag(NonPagedPool,
398                                 sizeof(struct _URB_PIPE_REQUEST),
399                                 USB_HUB_TAG);
400 
401     if (!Urb)
402     {
403         return STATUS_INSUFFICIENT_RESOURCES;
404     }
405 
406     RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
407 
408     Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
409     Urb->Hdr.Function = URB_FUNCTION_ABORT_PIPE;
410     Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
411 
412     Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
413                                    (PURB)Urb);
414 
415     if (NT_SUCCESS(Status))
416     {
417         KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
418                               Suspended,
419                               KernelMode,
420                               FALSE,
421                               NULL);
422     }
423 
424     ExFreePoolWithTag(Urb, USB_HUB_TAG);
425 
426     return Status;
427 }
428 
429 VOID
430 NTAPI
431 USBH_FdoCleanup(IN PUSBHUB_FDO_EXTENSION HubExtension)
432 {
433     PIRP IdleIrp = NULL;
434     PIRP WakeIrp = NULL;
435     PUSBHUB_PORT_DATA PortData;
436     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
437     PIRP PortIdleIrp = NULL;
438     PIRP PortWakeIrp = NULL;
439     PVOID DeviceHandle;
440     NTSTATUS Status;
441     USHORT Port;
442     UCHAR NumberPorts;
443     KIRQL Irql;
444 
445     DPRINT("USBH_FdoCleanup: HubExtension - %p\n", HubExtension);
446 
447     USBD_UnRegisterRootHubCallBack(HubExtension);
448 
449     HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STOPPING;
450 
451     if (HubExtension->ResetRequestCount)
452     {
453         IoCancelIrp(HubExtension->ResetPortIrp);
454 
455         KeWaitForSingleObject(&HubExtension->IdleEvent,
456                               Suspended,
457                               KernelMode,
458                               FALSE,
459                               NULL);
460     }
461 
462     IoFreeIrp(HubExtension->ResetPortIrp);
463 
464     HubExtension->ResetPortIrp = NULL;
465 
466     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
467     {
468         KeWaitForSingleObject(&HubExtension->IdleEvent,
469                               Suspended,
470                               KernelMode,
471                               FALSE,
472                               NULL);
473     }
474 
475     IoAcquireCancelSpinLock(&Irql);
476 
477     if (HubExtension->PendingWakeIrp)
478     {
479         WakeIrp = HubExtension->PendingWakeIrp;
480         HubExtension->PendingWakeIrp = NULL;
481     }
482 
483     if (HubExtension->PendingIdleIrp)
484     {
485         IdleIrp = HubExtension->PendingIdleIrp;
486         HubExtension->PendingIdleIrp = NULL;
487     }
488 
489     IoReleaseCancelSpinLock(Irql);
490 
491     if (WakeIrp)
492     {
493         USBH_HubCancelWakeIrp(HubExtension, WakeIrp);
494     }
495 
496     USBH_HubCompletePortWakeIrps(HubExtension, STATUS_DELETE_PENDING);
497 
498     if (IdleIrp)
499     {
500         USBH_HubCancelIdleIrp(HubExtension, IdleIrp);
501     }
502 
503     if (InterlockedDecrement(&HubExtension->PendingRequestCount) > 0)
504     {
505         KeWaitForSingleObject(&HubExtension->PendingRequestEvent,
506                               Suspended,
507                               KernelMode,
508                               FALSE,
509                               NULL);
510     }
511 
512     if (HubExtension->SCEIrp)
513     {
514         Status = USBH_AbortInterruptPipe(HubExtension);
515 
516         if (!NT_SUCCESS(Status) && IoCancelIrp(HubExtension->SCEIrp))
517         {
518             KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
519                                   Suspended,
520                                   KernelMode,
521                                   FALSE,
522                                   NULL);
523         }
524 
525         IoFreeIrp(HubExtension->SCEIrp);
526 
527         HubExtension->SCEIrp = NULL;
528     }
529 
530     if (!HubExtension->PortData ||
531         !HubExtension->HubDescriptor)
532     {
533         goto Exit;
534     }
535 
536     PortData = HubExtension->PortData;
537     NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
538 
539     for (Port = 0; Port < NumberPorts; Port++)
540     {
541         if (PortData[Port].DeviceObject)
542         {
543             PortExtension = PortData[Port].DeviceObject->DeviceExtension;
544 
545             IoAcquireCancelSpinLock(&Irql);
546 
547             PortIdleIrp = PortExtension->IdleNotificationIrp;
548 
549             if (PortIdleIrp)
550             {
551                 PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
552                 PortExtension->IdleNotificationIrp = NULL;
553 
554                 if (PortIdleIrp->Cancel)
555                 {
556                     PortIdleIrp = NULL;
557                 }
558 
559                 if (PortIdleIrp)
560                 {
561                     IoSetCancelRoutine(PortIdleIrp, NULL);
562                 }
563             }
564 
565             PortWakeIrp = PortExtension->PdoWaitWakeIrp;
566 
567             if (PortWakeIrp)
568             {
569                 PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE;
570                 PortExtension->PdoWaitWakeIrp = NULL;
571 
572                 if (PortWakeIrp->Cancel || !IoSetCancelRoutine(PortWakeIrp, NULL))
573                 {
574                     PortWakeIrp = NULL;
575 
576                     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
577                     {
578                         KeSetEvent(&HubExtension->PendingRequestEvent,
579                                    EVENT_INCREMENT,
580                                    FALSE);
581                     }
582                 }
583             }
584 
585             IoReleaseCancelSpinLock(Irql);
586 
587             if (PortIdleIrp)
588             {
589                 PortIdleIrp->IoStatus.Status = STATUS_CANCELLED;
590                 IoCompleteRequest(PortIdleIrp, IO_NO_INCREMENT);
591             }
592 
593             if (PortWakeIrp)
594             {
595                 USBH_CompletePowerIrp(HubExtension,
596                                       PortWakeIrp,
597                                       STATUS_CANCELLED);
598             }
599 
600             if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3))
601             {
602                 DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
603                                                           NULL);
604 
605                 if (DeviceHandle)
606                 {
607                     USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
608                 }
609 
610                 PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3;
611             }
612         }
613 
614         USBH_SyncDisablePort(HubExtension, Port + 1);
615     }
616 
617 Exit:
618 
619     if (HubExtension->SCEBitmap)
620     {
621         ExFreePoolWithTag(HubExtension->SCEBitmap, USB_HUB_TAG);
622     }
623 
624     if (HubExtension->HubDescriptor)
625     {
626         ExFreePoolWithTag(HubExtension->HubDescriptor, USB_HUB_TAG);
627     }
628 
629     if (HubExtension->HubConfigDescriptor)
630     {
631         ExFreePoolWithTag(HubExtension->HubConfigDescriptor, USB_HUB_TAG);
632     }
633 
634     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEVICE_STARTED;
635 
636     HubExtension->HubDescriptor = NULL;
637     HubExtension->HubConfigDescriptor = NULL;
638 
639     HubExtension->SCEIrp = NULL;
640     HubExtension->SCEBitmap = NULL;
641 }
642 
643 NTSTATUS
644 NTAPI
645 USBH_StartHubFdoDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
646                        IN PIRP Irp)
647 {
648     NTSTATUS Status;
649     ULONG DisableRemoteWakeup = 0;
650     ULONG HubCount = 0;
651     PUSB_DEVICE_HANDLE DeviceHandle;
652     USB_DEVICE_TYPE DeviceType;
653     DEVICE_CAPABILITIES  DeviceCapabilities;
654     BOOLEAN IsBusPowered;
655     static WCHAR DisableWakeValueName[] = L"DisableRemoteWakeup";
656 
657     DPRINT("USBH_StartHubFdoDevice: ... \n");
658 
659     KeInitializeEvent(&HubExtension->IdleEvent, NotificationEvent, FALSE);
660     KeInitializeEvent(&HubExtension->ResetEvent, NotificationEvent, TRUE);
661     KeInitializeEvent(&HubExtension->PendingRequestEvent, NotificationEvent, FALSE);
662     KeInitializeEvent(&HubExtension->LowerDeviceEvent, NotificationEvent, FALSE);
663     KeInitializeEvent(&HubExtension->StatusChangeEvent, NotificationEvent, TRUE);
664     KeInitializeEvent(&HubExtension->RootHubNotificationEvent,
665                       NotificationEvent,
666                       TRUE);
667 
668     KeInitializeSpinLock(&HubExtension->RelationsWorkerSpinLock);
669     KeInitializeSpinLock(&HubExtension->CheckIdleSpinLock);
670 
671     KeInitializeSemaphore(&HubExtension->ResetDeviceSemaphore, 1, 1);
672     KeInitializeSemaphore(&HubExtension->HubPortSemaphore, 1, 1);
673     KeInitializeSemaphore(&HubExtension->HubSemaphore, 1, 1);
674 
675     HubExtension->HubFlags = 0;
676     HubExtension->HubConfigDescriptor = NULL;
677     HubExtension->HubDescriptor = NULL;
678     HubExtension->SCEIrp = NULL;
679     HubExtension->SCEBitmap = NULL;
680     HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
681     HubExtension->PendingRequestCount = 1;
682     HubExtension->ResetRequestCount = 0;
683     HubExtension->PendingIdleIrp = NULL;
684     HubExtension->PendingWakeIrp = NULL;
685 
686     InitializeListHead(&HubExtension->PdoList);
687 
688     HubExtension->HubFlags |= USBHUB_FDO_FLAG_WITEM_INIT;
689     InitializeListHead(&HubExtension->WorkItemList);
690     KeInitializeSpinLock(&HubExtension->WorkItemSpinLock);
691 
692     IoCopyCurrentIrpStackLocationToNext(Irp);
693 
694     IoSetCompletionRoutine(Irp,
695                            USBH_HubPnPIrpComplete,
696                            HubExtension,
697                            TRUE,
698                            TRUE,
699                            TRUE);
700 
701     if (IoCallDriver(HubExtension->LowerDevice, Irp) == STATUS_PENDING)
702     {
703         KeWaitForSingleObject(&HubExtension->LowerDeviceEvent,
704                               Suspended,
705                               KernelMode,
706                               FALSE,
707                               NULL);
708     }
709 
710     HubExtension->RootHubPdo = NULL;
711 
712     Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice,
713                                     &HubExtension->RootHubPdo,
714                                     &HubExtension->RootHubPdo2);
715 
716     if (!NT_SUCCESS(Status))
717     {
718         DPRINT1("USBH_SyncGetRootHubPdo() failed - %lX\n", Status);
719         goto ErrorExit;
720     }
721 
722     USBH_WriteFailReasonID(HubExtension->LowerPDO, USBHUB_FAIL_NO_FAIL);
723 
724     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
725     {
726         DPRINT1("USBH_StartHubFdoDevice: USBHUB_FDO_FLAG_DEVICE_FAILED - TRUE\n");
727         Status = STATUS_UNSUCCESSFUL;
728         goto ErrorExit;
729     }
730 
731     HubExtension->HubFlags |= USBHUB_FDO_FLAG_REMOTE_WAKEUP;
732 
733     Status = USBD_GetPdoRegistryParameter(HubExtension->LowerPDO,
734                                           &DisableRemoteWakeup,
735                                           sizeof(DisableRemoteWakeup),
736                                           DisableWakeValueName,
737                                           sizeof(DisableWakeValueName));
738 
739     if (NT_SUCCESS(Status) && DisableRemoteWakeup)
740     {
741         DPRINT("USBH_StartHubFdoDevice: DisableRemoteWakeup - TRUE\n");
742         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_REMOTE_WAKEUP;
743     }
744 
745     HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
746 
747     USBH_SyncGetHubCount(HubExtension->LowerDevice,
748                          &HubCount);
749 
750     Status = USBHUB_GetBusInterface(HubExtension->RootHubPdo,
751                                     &HubExtension->BusInterface);
752 
753     if (!NT_SUCCESS(Status))
754     {
755         DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterface() failed - %lX\n",
756                 Status);
757         goto ErrorExit;
758     }
759 
760     Status = USBHUB_GetBusInterfaceUSBDI(HubExtension->LowerDevice,
761                                          &HubExtension->BusInterfaceUSBDI);
762 
763     if (!NT_SUCCESS(Status))
764     {
765         DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterfaceUSBDI() failed - %lX\n",
766                 Status);
767         goto ErrorExit;
768     }
769 
770     DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
771 
772     if (DeviceHandle)
773     {
774         Status = USBH_GetDeviceType(HubExtension, DeviceHandle, &DeviceType);
775 
776         if (!NT_SUCCESS(Status))
777         {
778             DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceType() failed - %lX\n",
779                     Status);
780 
781             goto ErrorExit;
782         }
783 
784         if (DeviceType == Usb20Device)
785         {
786             HubExtension->HubFlags |= USBHUB_FDO_FLAG_USB20_HUB;
787         }
788     }
789 
790     if (HubCount > USBHUB_MAX_CASCADE_LEVELS)
791     {
792         PUSBHUB_PORT_PDO_EXTENSION ParentPdoExtension;
793         PUSBHUB_FDO_EXTENSION ParentHubExtension;
794         USHORT ParentPort;
795         PUSBHUB_PORT_DATA PortData;
796 
797         DPRINT1("USBH_StartHubFdoDevice: HubCount > 6 - %x\n", HubCount);
798 
799         USBH_WriteFailReasonID(HubExtension->LowerPDO,
800                                USBHUB_FAIL_NESTED_TOO_DEEPLY);
801 
802         ParentPdoExtension = HubExtension->LowerPDO->DeviceExtension;
803         ParentHubExtension = ParentPdoExtension->HubExtension;
804 
805         ParentPort = ParentPdoExtension->PortNumber - 1;
806         PortData = &ParentHubExtension->PortData[ParentPort];
807         PortData->ConnectionStatus = DeviceHubNestedTooDeeply;
808 
809         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
810     }
811 
812     USBH_QueryCapabilities(HubExtension->LowerDevice, &DeviceCapabilities);
813 
814     HubExtension->SystemWake = DeviceCapabilities.SystemWake;
815     HubExtension->DeviceWake = DeviceCapabilities.DeviceWake;
816 
817     RtlCopyMemory(HubExtension->DeviceState,
818                   &DeviceCapabilities.DeviceState,
819                   POWER_SYSTEM_MAXIMUM * sizeof(DEVICE_POWER_STATE));
820 
821     Status = USBH_GetDeviceDescriptor(HubExtension->Common.SelfDevice,
822                                       &HubExtension->HubDeviceDescriptor);
823 
824     if (!NT_SUCCESS(Status))
825     {
826         DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceDescriptor() failed - %lX\n",
827                 Status);
828         goto ErrorExit;
829     }
830 
831     Status = USBH_GetConfigurationDescriptor(HubExtension->Common.SelfDevice,
832                                              &HubExtension->HubConfigDescriptor);
833 
834     if (!NT_SUCCESS(Status))
835     {
836         DPRINT1("USBH_StartHubFdoDevice: USBH_GetConfigurationDescriptor() failed - %lX\n",
837                 Status);
838         goto ErrorExit;
839     }
840 
841     Status = USBH_SyncGetHubDescriptor(HubExtension);
842 
843     if (!NT_SUCCESS(Status))
844     {
845         DPRINT1("USBH_StartHubFdoDevice: USBH_SyncGetHubDescriptor() failed - %lX\n",
846                 Status);
847         goto ErrorExit;
848     }
849 
850     IsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice,
851                                         HubExtension->HubConfigDescriptor);
852 
853     if (IsBusPowered)
854     {
855         /* bus-powered hub is allowed a maximum of 100 mA only for each port */
856         HubExtension->MaxPowerPerPort = 100;
857 
858         /* can have 4 ports (4 * 100 mA) and 100 mA remains for itself;
859            expressed in 2 mA units (i.e., 250 = 500 mA). */
860         HubExtension->HubConfigDescriptor->MaxPower = 250;
861     }
862     else
863     {
864         /* self-powered hub is allowed a maximum of 500 mA for each port */
865         HubExtension->MaxPowerPerPort = 500;
866     }
867 
868     Status = USBH_OpenConfiguration(HubExtension);
869 
870     if (!NT_SUCCESS(Status))
871     {
872         DPRINT1("USBH_StartHubFdoDevice: USBH_OpenConfiguration() failed - %lX\n",
873                 Status);
874         goto ErrorExit;
875     }
876 
877     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
878     {
879         Status = USBD_Initialize20Hub(HubExtension);
880     }
881 
882     if (!NT_SUCCESS(Status))
883     {
884         goto ErrorExit;
885     }
886 
887     HubExtension->SCEIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize,
888                                          FALSE);
889 
890     HubExtension->ResetPortIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize,
891                                                FALSE);
892 
893     if (!HubExtension->SCEIrp || !HubExtension->ResetPortIrp)
894     {
895         Status = STATUS_INSUFFICIENT_RESOURCES;
896         goto ErrorExit;
897     }
898 
899     HubExtension->SCEBitmapLength = HubExtension->PipeInfo.MaximumPacketSize;
900 
901     HubExtension->SCEBitmap = ExAllocatePoolWithTag(NonPagedPool,
902                                                     HubExtension->SCEBitmapLength,
903                                                     USB_HUB_TAG);
904 
905     if (!HubExtension->SCEBitmap)
906     {
907         Status = STATUS_INSUFFICIENT_RESOURCES;
908         goto ErrorExit;
909     }
910 
911     RtlZeroMemory(HubExtension->SCEBitmap, HubExtension->SCEBitmapLength);
912 
913     Status = USBH_SyncPowerOnPorts(HubExtension);
914 
915     if (!NT_SUCCESS(Status))
916     {
917         goto ErrorExit;
918     }
919     else
920     {
921         USHORT Port;
922 
923         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STARTED;
924 
925         for (Port = 1;
926              Port <= HubExtension->HubDescriptor->bNumberOfPorts;
927              Port++)
928         {
929             USBH_SyncClearPortStatus(HubExtension,
930                                      Port,
931                                      USBHUB_FEATURE_C_PORT_CONNECTION);
932         }
933     }
934 
935     if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
936     {
937         USBD_RegisterRootHubCallBack(HubExtension);
938     }
939     else
940     {
941         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
942         USBH_SubmitStatusChangeTransfer(HubExtension);
943     }
944 
945     goto Exit;
946 
947   ErrorExit:
948 
949     if (HubExtension->HubDescriptor)
950     {
951         ExFreePoolWithTag(HubExtension->HubDescriptor, USB_HUB_TAG);
952         HubExtension->HubDescriptor = NULL;
953     }
954 
955     if (HubExtension->SCEIrp)
956     {
957         IoFreeIrp(HubExtension->SCEIrp);
958         HubExtension->SCEIrp = NULL;
959     }
960 
961     if (HubExtension->ResetPortIrp)
962     {
963         IoFreeIrp(HubExtension->ResetPortIrp);
964         HubExtension->ResetPortIrp = NULL;
965     }
966 
967     if (HubExtension->SCEBitmap)
968     {
969         ExFreePoolWithTag(HubExtension->SCEBitmap, USB_HUB_TAG);
970         HubExtension->SCEBitmap = NULL;
971     }
972 
973     if (HubExtension->HubConfigDescriptor)
974     {
975         ExFreePoolWithTag(HubExtension->HubConfigDescriptor, USB_HUB_TAG);
976         HubExtension->HubConfigDescriptor = NULL;
977     }
978 
979   Exit:
980 
981     USBH_CompleteIrp(Irp, Status);
982 
983     return Status;
984 }
985 
986 NTSTATUS
987 NTAPI
988 USBH_FdoStartDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
989                     IN PIRP Irp)
990 {
991     NTSTATUS Status;
992 
993     DPRINT("USBH_FdoStartDevice: HubExtension - %p\n", HubExtension);
994 
995     HubExtension->RootHubPdo = NULL;
996 
997     Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice,
998                                     &HubExtension->RootHubPdo,
999                                     &HubExtension->RootHubPdo2);
1000 
1001     if (NT_SUCCESS(Status))
1002     {
1003         if (HubExtension->RootHubPdo)
1004         {
1005             Status = USBH_StartHubFdoDevice(HubExtension, Irp);
1006         }
1007         else
1008         {
1009             DPRINT1("USBH_FdoStartDevice: FIXME. start ParentDevice\n");
1010             DbgBreakPoint();
1011         }
1012     }
1013     else
1014     {
1015         DPRINT1("USBH_FdoStartDevice: FIXME. USBH_SyncGetRootHubPdo return - %lX\n",
1016                 Status);
1017 
1018         DbgBreakPoint();
1019         USBH_CompleteIrp(Irp, Status);
1020     }
1021 
1022     return Status;
1023 }
1024 
1025 NTSTATUS
1026 NTAPI
1027 USBH_FdoQueryBusRelations(IN PUSBHUB_FDO_EXTENSION HubExtension,
1028                           IN PIRP Irp)
1029 {
1030     PDEVICE_RELATIONS DeviceRelations = NULL;
1031     NTSTATUS Status = STATUS_SUCCESS;
1032     LIST_ENTRY GhostPdoList;
1033     KIRQL OldIrql;
1034     PLIST_ENTRY PdoList;
1035     UCHAR NumberPorts;
1036     USHORT Port;
1037     USHORT GhostPort;
1038     PUSBHUB_PORT_DATA PortData;
1039     PDEVICE_OBJECT PdoDevice;
1040     PUSBHUB_PORT_PDO_EXTENSION PdoExtension;
1041     PUSBHUB_PORT_PDO_EXTENSION pdoExtension;
1042     NTSTATUS NtStatus;
1043     PVOID SerialNumber;
1044     PVOID DeviceHandle;
1045     USB_PORT_STATUS UsbPortStatus;
1046     PLIST_ENTRY Entry;
1047     ULONG Length;
1048 
1049     DPRINT_ENUM("USBH_FdoQueryBusRelations: HubFlags - %lX\n",
1050                 HubExtension->HubFlags);
1051 
1052     if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED))
1053     {
1054        Status = STATUS_INVALID_DEVICE_STATE;
1055        goto RelationsWorker;
1056     }
1057 
1058     if (!HubExtension->HubDescriptor)
1059     {
1060         Status = STATUS_UNSUCCESSFUL;
1061         goto RelationsWorker;
1062     }
1063 
1064     if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
1065     {
1066         // FIXME: this delay makes devices discovery during early boot more reliable
1067         LARGE_INTEGER Interval;
1068         Status = STATUS_SUCCESS;
1069         IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1070         Interval.QuadPart = -10000LL * 1000; // 1 sec.
1071         KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1072 
1073         DPRINT_ENUM("USBH_FdoQueryBusRelations: Skip enumeration\n");
1074         goto RelationsWorker;
1075     }
1076 
1077     InterlockedIncrement(&HubExtension->PendingRequestCount);
1078 
1079     KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
1080                           Executive,
1081                           KernelMode,
1082                           FALSE,
1083                           NULL);
1084 
1085     NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
1086     DPRINT_ENUM("USBH_FdoQueryBusRelations: NumberPorts - %x\n", NumberPorts);
1087 
1088     Length = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1089              NumberPorts * sizeof(PDEVICE_OBJECT);
1090 
1091     if (Irp->IoStatus.Information)
1092     {
1093         DPRINT1("FIXME: leaking old bus relations\n");
1094     }
1095 
1096     DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
1097 
1098     if (!DeviceRelations)
1099     {
1100         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
1101 
1102         KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
1103                            LOW_REALTIME_PRIORITY,
1104                            1,
1105                            FALSE);
1106 
1107         if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
1108         {
1109             KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
1110         }
1111 
1112         Status = STATUS_INSUFFICIENT_RESOURCES;
1113         goto RelationsWorker;
1114     }
1115 
1116     RtlZeroMemory(DeviceRelations, Length);
1117 
1118     DeviceRelations->Count = 0;
1119 
1120 EnumStart:
1121 
1122     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
1123     {
1124         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
1125 
1126         KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
1127                            LOW_REALTIME_PRIORITY,
1128                            1,
1129                            FALSE);
1130 
1131         if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
1132         {
1133             KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
1134         }
1135 
1136         Status = STATUS_SUCCESS;
1137         goto RelationsWorker;
1138     }
1139 
1140     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_ENUM_POST_RECOVER;
1141 
1142     for (Port = 1; Port <= NumberPorts; Port++)
1143     {
1144         PortData = &HubExtension->PortData[Port - 1];
1145 
1146         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
1147         {
1148             continue;
1149         }
1150 
1151         Status = USBH_SyncGetPortStatus(HubExtension,
1152                                         Port,
1153                                         &PortData->PortStatus,
1154                                         sizeof(USB_PORT_STATUS_AND_CHANGE));
1155 
1156         if (!NT_SUCCESS(Status))
1157         {
1158             DPRINT_ENUM("USBH_FdoQueryBusRelations: Status - %X\n", Status);
1159             HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
1160             DeviceRelations->Count = 0;
1161             goto EnumStart;
1162         }
1163 
1164         DPRINT_ENUM("USBH_FdoQueryBusRelations: Port - %x, ConnectStatus - %x\n",
1165                     Port,
1166                     PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus);
1167 
1168         PdoDevice = PortData->DeviceObject;
1169 
1170         if (PortData->DeviceObject)
1171         {
1172             PdoExtension = PdoDevice->DeviceExtension;
1173 
1174             if (PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
1175             {
1176                 PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
1177             }
1178         }
1179 
1180         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
1181         {
1182             DPRINT1("USBH_FdoQueryBusRelations: DbgBreakPoint() \n");
1183             DbgBreakPoint();
1184         }
1185 
1186         if (!PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
1187         {
1188             if (PdoDevice)
1189             {
1190                 PdoExtension = PdoDevice->DeviceExtension;
1191 
1192                 PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING;
1193                 PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
1194 
1195                 SerialNumber = InterlockedExchangePointer((PVOID)&PdoExtension->SerialNumber,
1196                                                           NULL);
1197 
1198                 if (SerialNumber)
1199                 {
1200                     ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
1201                 }
1202 
1203                 DeviceHandle = InterlockedExchangePointer(&PdoExtension->DeviceHandle,
1204                                                           NULL);
1205 
1206                 if (DeviceHandle)
1207                 {
1208                     USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
1209                     USBH_SyncDisablePort(HubExtension, Port);
1210                 }
1211             }
1212 
1213             PortData->DeviceObject = NULL;
1214             PortData->ConnectionStatus = NoDeviceConnected;
1215             continue;
1216         }
1217 
1218         if (PdoDevice)
1219         {
1220             ObReferenceObject(PdoDevice);
1221 
1222             PdoDevice->Flags |= DO_POWER_PAGABLE;
1223             PdoDevice->Flags &= ~DO_DEVICE_INITIALIZING;
1224 
1225             DeviceRelations->Objects[DeviceRelations->Count++] = PdoDevice;
1226 
1227             PdoExtension = PdoDevice->DeviceExtension;
1228             PdoExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D1_OR_D2;
1229 
1230             continue;
1231         }
1232 
1233         USBH_Wait(100);
1234 
1235         NtStatus = USBH_SyncResetPort(HubExtension, Port);
1236 
1237         if (!NT_SUCCESS(NtStatus))
1238         {
1239             if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
1240             {
1241                 PortData->DeviceObject = NULL;
1242                 PortData->ConnectionStatus = NoDeviceConnected;
1243                 continue;
1244             }
1245         }
1246         else
1247         {
1248             NtStatus = USBH_SyncGetPortStatus(HubExtension,
1249                                               Port,
1250                                               &PortData->PortStatus,
1251                                               sizeof(USB_PORT_STATUS_AND_CHANGE));
1252 
1253             UsbPortStatus = PortData->PortStatus.PortStatus;
1254 
1255             if (NT_SUCCESS(NtStatus))
1256             {
1257                 ULONG ix = 0;
1258 
1259                 for (NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix);
1260                      !NT_SUCCESS(NtStatus);
1261                      NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix))
1262                 {
1263                     USBH_Wait(500);
1264 
1265                     if (ix >= 2)
1266                     {
1267                         break;
1268                     }
1269 
1270                     if (PortData->DeviceObject)
1271                     {
1272                         IoDeleteDevice(PortData->DeviceObject);
1273                         PortData->DeviceObject = NULL;
1274                         PortData->ConnectionStatus = NoDeviceConnected;
1275                     }
1276 
1277                     USBH_SyncResetPort(HubExtension, Port);
1278 
1279                     ix++;
1280                 }
1281 
1282                 if (NT_SUCCESS(NtStatus))
1283                 {
1284                     PdoExtension = PortData->DeviceObject->DeviceExtension;
1285 
1286                     if (!(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_LOW_SPEED) &&
1287                         !(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_HIGH_SPEED) &&
1288                         !(HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB))
1289                     {
1290                         DPRINT1("USBH_FdoQueryBusRelations: FIXME USBH_DeviceIs2xDualMode()\n");
1291 
1292                         if (0)//USBH_DeviceIs2xDualMode(PdoExtension))
1293                         {
1294                             PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_HS_USB1_DUALMODE;
1295                         }
1296                     }
1297 
1298                     ObReferenceObject(PortData->DeviceObject);
1299 
1300                     DeviceRelations->Objects[DeviceRelations->Count] = PortData->DeviceObject;
1301 
1302                     PortData->DeviceObject->Flags |= DO_POWER_PAGABLE;
1303                     PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1304 
1305                     DeviceRelations->Count++;
1306 
1307                     PortData->ConnectionStatus = DeviceConnected;
1308 
1309                     continue;
1310                 }
1311             }
1312         }
1313 
1314         PortData->ConnectionStatus = DeviceFailedEnumeration;
1315 
1316         if (NT_ERROR(USBH_SyncDisablePort(HubExtension, Port)))
1317         {
1318             HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
1319         }
1320 
1321         if (PortData->DeviceObject)
1322         {
1323             ObReferenceObject(PortData->DeviceObject);
1324             PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1325             DeviceRelations->Objects[DeviceRelations->Count++] = PortData->DeviceObject;
1326         }
1327     }
1328 
1329     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
1330 
1331     KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
1332                        LOW_REALTIME_PRIORITY,
1333                        1,
1334                        FALSE);
1335 
1336     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
1337     {
1338         KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
1339     }
1340 
1341 RelationsWorker:
1342 
1343     Irp->IoStatus.Status = Status;
1344 
1345     if (!NT_SUCCESS(Status))
1346     {
1347         //Irp->IoStatus.Information = 0;
1348 
1349         if (DeviceRelations)
1350         {
1351             ExFreePoolWithTag(DeviceRelations, USB_HUB_TAG);
1352         }
1353 
1354         USBH_CompleteIrp(Irp, Status);
1355 
1356         return Status;
1357     }
1358 
1359     KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &OldIrql);
1360 
1361     if (DeviceRelations && DeviceRelations->Count)
1362     {
1363         for (Port = 0; Port < DeviceRelations->Count; Port++)
1364         {
1365             PdoDevice = DeviceRelations->Objects[Port];
1366             Entry = HubExtension->PdoList.Flink;
1367 
1368             while (Entry != &HubExtension->PdoList)
1369             {
1370                 pdoExtension = CONTAINING_RECORD(Entry,
1371                                                  USBHUB_PORT_PDO_EXTENSION,
1372                                                  PortLink);
1373 
1374                 if (pdoExtension == PdoDevice->DeviceExtension)
1375                 {
1376                     PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_GHOST_DEVICE;
1377                     goto PortNext;
1378                 }
1379 
1380                 Entry = Entry->Flink;
1381             }
1382 
1383             PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_DEVICE_PRESENT;
1384 
1385     PortNext:;
1386         }
1387 
1388         for (Port = 0; Port < DeviceRelations->Count; Port++)
1389         {
1390             PdoDevice = DeviceRelations->Objects[Port];
1391 
1392             if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE)
1393             {
1394                 for (GhostPort = Port;
1395                      GhostPort < DeviceRelations->Count;
1396                      GhostPort++)
1397                 {
1398                     DeviceRelations->Objects[GhostPort] =
1399                     DeviceRelations->Objects[GhostPort + 1];
1400                 }
1401 
1402                 ObDereferenceObject(PdoDevice);
1403 
1404                 DeviceRelations->Count--;
1405 
1406                 if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)
1407                 {
1408                     PdoExt(PdoDevice)->EnumFlags &= ~USBHUB_ENUM_FLAG_GHOST_DEVICE;
1409                 }
1410             }
1411         }
1412     }
1413 
1414     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1415 
1416     InitializeListHead(&GhostPdoList);
1417     PdoList = &HubExtension->PdoList;
1418 
1419     while (!IsListEmpty(PdoList))
1420     {
1421         Entry = RemoveHeadList(PdoList);
1422 
1423         PdoExtension = CONTAINING_RECORD(Entry,
1424                                          USBHUB_PORT_PDO_EXTENSION,
1425                                          PortLink);
1426 
1427         PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
1428 
1429         if (PdoExtension->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE)
1430         {
1431             InsertTailList(&GhostPdoList, &PdoExtension->PortLink);
1432         }
1433     }
1434 
1435     KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, OldIrql);
1436 
1437     while (!IsListEmpty(&GhostPdoList))
1438     {
1439         Entry = RemoveHeadList(&GhostPdoList);
1440 
1441         PdoExtension = CONTAINING_RECORD(Entry,
1442                                          USBHUB_PORT_PDO_EXTENSION,
1443                                          PortLink);
1444 
1445         IoDeleteDevice(PdoExtension->Common.SelfDevice);
1446     }
1447 
1448     return USBH_PassIrp(HubExtension->LowerDevice, Irp);
1449 }
1450 
1451 NTSTATUS
1452 NTAPI
1453 USBH_FdoStopDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
1454                    IN PIRP Irp)
1455 {
1456     DPRINT1("USBH_FdoStopDevice: UNIMPLEMENTED. FIXME\n");
1457     DbgBreakPoint();
1458     return STATUS_SUCCESS;
1459 }
1460 
1461 NTSTATUS
1462 NTAPI
1463 USBH_FdoRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
1464                      IN PIRP Irp)
1465 {
1466     PUSB_HUB_DESCRIPTOR HubDescriptor;
1467     PUSBHUB_PORT_DATA PortData;
1468     USHORT NumPorts;
1469     USHORT ix;
1470     PDEVICE_OBJECT PortDevice;
1471     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
1472     NTSTATUS Status;
1473 
1474     DPRINT("USBH_FdoRemoveDevice: HubExtension - %p\n", HubExtension);
1475 
1476     HubDescriptor = HubExtension->HubDescriptor;
1477 
1478     if (HubDescriptor && HubExtension->PortData)
1479     {
1480         NumPorts = HubDescriptor->bNumberOfPorts;
1481 
1482         for (ix = 0; ix < NumPorts; ++ix)
1483         {
1484             PortData = HubExtension->PortData + ix;
1485 
1486             PortDevice = PortData->DeviceObject;
1487 
1488             if (PortDevice)
1489             {
1490                 PortData->PortStatus.AsUlong32 = 0;
1491                 PortData->DeviceObject = NULL;
1492 
1493                 PortExtension = PortDevice->DeviceExtension;
1494                 PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
1495 
1496                 USBH_PdoRemoveDevice(PortExtension, HubExtension);
1497             }
1498         }
1499     }
1500 
1501     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
1502     {
1503         USBH_FdoCleanup(HubExtension);
1504     }
1505 
1506     if (HubExtension->PortData)
1507     {
1508         ExFreePoolWithTag(HubExtension->PortData, USB_HUB_TAG);
1509         HubExtension->PortData = NULL;
1510     }
1511 
1512     DPRINT1("USBH_FdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
1513 
1514     Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
1515 
1516     IoDetachDevice(HubExtension->LowerDevice);
1517     IoDeleteDevice(HubExtension->Common.SelfDevice);
1518 
1519     return Status;
1520 }
1521 
1522 VOID
1523 NTAPI
1524 USBH_FdoSurpriseRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
1525                              IN PIRP Irp)
1526 {
1527     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
1528     PUSBHUB_PORT_DATA PortData;
1529     ULONG NumberPorts;
1530     ULONG Port;
1531 
1532     DPRINT("USBH_FdoSurpriseRemoveDevice: HubExtension - %p, Irp - %p\n",
1533            HubExtension,
1534            Irp);
1535 
1536     if (!HubExtension->PortData ||
1537         !HubExtension->HubDescriptor)
1538     {
1539         return;
1540     }
1541 
1542     PortData = HubExtension->PortData;
1543     NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
1544 
1545     for (Port = 0; Port < NumberPorts; Port++)
1546     {
1547         if (PortData[Port].DeviceObject)
1548         {
1549             PortExtension = PdoExt(PortData[Port].DeviceObject);
1550             PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING;
1551             PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
1552 
1553             PortData[Port].DeviceObject = NULL;
1554             PortData[Port].ConnectionStatus = NoDeviceConnected;
1555         }
1556     }
1557 }
1558 
1559 NTSTATUS
1560 NTAPI
1561 USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
1562                 IN PIRP Irp)
1563 {
1564     ULONG IdType;
1565     WCHAR Buffer[200];
1566     PWCHAR EndBuffer;
1567     size_t Remaining = sizeof(Buffer);
1568     size_t Length;
1569     PWCHAR Id = NULL;
1570     NTSTATUS Status = STATUS_SUCCESS;
1571     PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
1572     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
1573 
1574     IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
1575     DeviceDescriptor = &PortExtension->DeviceDescriptor;
1576     InterfaceDescriptor = &PortExtension->InterfaceDescriptor;
1577 
1578     RtlZeroMemory(Buffer, sizeof(Buffer));
1579 
1580     switch (IdType)
1581     {
1582         case BusQueryDeviceID:
1583             DPRINT("USBH_PdoQueryId: BusQueryDeviceID\n");
1584 
1585             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
1586             {
1587                 DPRINT("USBH_PdoQueryId: USBHUB_PDO_FLAG_INIT_PORT_FAILED\n");
1588                 RtlStringCbPrintfExW(Buffer,
1589                                      Remaining,
1590                                      NULL,
1591                                      &Remaining,
1592                                      0,
1593                                      L"USB\\Vid_0000&Pid_0000");
1594             }
1595             else
1596             {
1597                 RtlStringCbPrintfExW(Buffer,
1598                                      Remaining,
1599                                      NULL,
1600                                      &Remaining,
1601                                      0,
1602                                      L"USB\\Vid_%04x&Pid_%04x",
1603                                      DeviceDescriptor->idVendor,
1604                                      DeviceDescriptor->idProduct);
1605             }
1606 
1607             Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL));
1608 
1609             Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
1610 
1611             if (!Id)
1612             {
1613                 break;
1614             }
1615 
1616             RtlCopyMemory(Id, Buffer, Length);
1617             DPRINT("USBH_PdoQueryId: BusQueryDeviceID - %S\n", Id);
1618             break;
1619 
1620         case BusQueryHardwareIDs:
1621             DPRINT("USBH_PdoQueryId: BusQueryHardwareIDs\n");
1622 
1623             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
1624             {
1625                 DPRINT("USBH_PdoQueryId: USBHUB_PDO_FLAG_INIT_PORT_FAILED\n");
1626 
1627                 RtlStringCbPrintfExW(Buffer,
1628                                      Remaining,
1629                                      NULL,
1630                                      &Remaining,
1631                                      0,
1632                                      L"USB\\UNKNOWN");
1633             }
1634             else
1635             {
1636                 RtlStringCbPrintfExW(Buffer,
1637                                      Remaining,
1638                                      &EndBuffer,
1639                                      &Remaining,
1640                                      0,
1641                                      L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
1642                                      DeviceDescriptor->idVendor,
1643                                      DeviceDescriptor->idProduct,
1644                                      DeviceDescriptor->bcdDevice);
1645 
1646                 EndBuffer++;
1647                 Remaining -= sizeof(UNICODE_NULL);
1648 
1649                 RtlStringCbPrintfExW(EndBuffer,
1650                                      Remaining,
1651                                      NULL,
1652                                      &Remaining,
1653                                      0,
1654                                      L"USB\\Vid_%04x&Pid_%04x",
1655                                      DeviceDescriptor->idVendor,
1656                                      DeviceDescriptor->idProduct);
1657             }
1658 
1659             Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL));
1660 
1661             Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
1662 
1663             if (!Id)
1664             {
1665                 break;
1666             }
1667 
1668             RtlCopyMemory(Id, Buffer, Length);
1669 
1670             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
1671             {
1672                 DPRINT("USBH_PdoQueryId: BusQueryHardwareID - %S\n", Id);
1673             }
1674             else
1675             {
1676                 USBHUB_DumpingIDs(Id);
1677             }
1678 
1679             break;
1680 
1681         case BusQueryCompatibleIDs:
1682             DPRINT("USBH_PdoQueryId: BusQueryCompatibleIDs\n");
1683 
1684             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
1685             {
1686                 DPRINT("USBH_PdoQueryId: USBHUB_PDO_FLAG_INIT_PORT_FAILED\n");
1687 
1688                 RtlStringCbPrintfExW(Buffer,
1689                                      Remaining,
1690                                      NULL,
1691                                      &Remaining,
1692                                      0,
1693                                      L"USB\\UNKNOWN");
1694             }
1695             else if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_MULTI_INTERFACE)
1696             {
1697                 RtlStringCbPrintfExW(Buffer,
1698                                      Remaining,
1699                                      &EndBuffer,
1700                                      &Remaining,
1701                                      0,
1702                                      L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
1703                                      InterfaceDescriptor->bInterfaceClass,
1704                                      InterfaceDescriptor->bInterfaceSubClass,
1705                                      InterfaceDescriptor->bInterfaceProtocol);
1706 
1707                 EndBuffer++;
1708                 Remaining -= sizeof(UNICODE_NULL);
1709 
1710                 RtlStringCbPrintfExW(EndBuffer,
1711                                      Remaining,
1712                                      &EndBuffer,
1713                                      &Remaining,
1714                                      0,
1715                                      L"USB\\DevClass_%02x&SubClass_%02x",
1716                                      InterfaceDescriptor->bInterfaceClass,
1717                                      InterfaceDescriptor->bInterfaceSubClass);
1718 
1719                 EndBuffer++;
1720                 Remaining -= sizeof(UNICODE_NULL);
1721 
1722                 RtlStringCbPrintfExW(EndBuffer,
1723                                      Remaining,
1724                                      &EndBuffer,
1725                                      &Remaining,
1726                                      0,
1727                                      L"USB\\DevClass_%02x",
1728                                      InterfaceDescriptor->bInterfaceClass);
1729 
1730                 EndBuffer++;
1731                 Remaining -= sizeof(UNICODE_NULL);
1732 
1733                 RtlStringCbPrintfExW(EndBuffer,
1734                                      Remaining,
1735                                      NULL,
1736                                      &Remaining,
1737                                      0,
1738                                      L"USB\\COMPOSITE");
1739             }
1740             else
1741             {
1742                 RtlStringCbPrintfExW(Buffer,
1743                                      Remaining,
1744                                      &EndBuffer,
1745                                      &Remaining,
1746                                      0,
1747                                      L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
1748                                      InterfaceDescriptor->bInterfaceClass,
1749                                      InterfaceDescriptor->bInterfaceSubClass,
1750                                      InterfaceDescriptor->bInterfaceProtocol);
1751 
1752                 EndBuffer++;
1753                 Remaining -= sizeof(UNICODE_NULL);
1754 
1755                 RtlStringCbPrintfExW(EndBuffer,
1756                                      Remaining,
1757                                      &EndBuffer,
1758                                      &Remaining,
1759                                      0,
1760                                      L"USB\\Class_%02x&SubClass_%02x",
1761                                      InterfaceDescriptor->bInterfaceClass,
1762                                      InterfaceDescriptor->bInterfaceSubClass);
1763 
1764                 EndBuffer++;
1765                 Remaining -= sizeof(UNICODE_NULL);
1766 
1767                 RtlStringCbPrintfExW(EndBuffer,
1768                                      Remaining,
1769                                      NULL,
1770                                      &Remaining,
1771                                      0,
1772                                      L"USB\\Class_%02x",
1773                                      InterfaceDescriptor->bInterfaceClass);
1774             }
1775 
1776             Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL));
1777 
1778             Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
1779 
1780             if (!Id)
1781             {
1782                 break;
1783             }
1784 
1785             RtlCopyMemory(Id, Buffer, Length);
1786 
1787             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
1788             {
1789                 DPRINT("USBH_PdoQueryId: BusQueryCompatibleID - %S\n", Id);
1790             }
1791             else
1792             {
1793                 USBHUB_DumpingIDs(Id);
1794             }
1795 
1796             break;
1797 
1798         case BusQueryInstanceID:
1799             DPRINT("USBH_PdoQueryId: BusQueryInstanceID\n");
1800 
1801             if (PortExtension->SerialNumber)
1802             {
1803                 Id = ExAllocatePoolWithTag(PagedPool,
1804                                            PortExtension->SN_DescriptorLength,
1805                                            USB_HUB_TAG);
1806 
1807                 if (Id)
1808                 {
1809                     RtlZeroMemory(Id, PortExtension->SN_DescriptorLength);
1810 
1811                     RtlCopyMemory(Id,
1812                                   PortExtension->SerialNumber,
1813                                   PortExtension->SN_DescriptorLength);
1814                 }
1815             }
1816             else
1817             {
1818                  Length = sizeof(PortExtension->InstanceID) +
1819                           sizeof(UNICODE_NULL);
1820 
1821                  Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
1822 
1823                  if (Id)
1824                  {
1825                      RtlZeroMemory(Id, Length);
1826 
1827                      RtlCopyMemory(Id,
1828                                    PortExtension->InstanceID,
1829                                    sizeof(PortExtension->InstanceID));
1830                  }
1831             }
1832 
1833             DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id);
1834             break;
1835 
1836         default:
1837             DPRINT1("USBH_PdoQueryId: unknown query id type 0x%lx\n", IdType);
1838             return Irp->IoStatus.Status;
1839     }
1840 
1841     Irp->IoStatus.Information = (ULONG_PTR)Id;
1842 
1843     if (!Id)
1844     {
1845         Status = STATUS_INSUFFICIENT_RESOURCES;
1846     }
1847 
1848     return Status;
1849 }
1850 
1851 NTSTATUS
1852 NTAPI
1853 USBH_PdoQueryDeviceText(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
1854                         IN PIRP Irp)
1855 {
1856     PDEVICE_OBJECT DeviceObject;
1857     PIO_STACK_LOCATION IoStack;
1858     DEVICE_TEXT_TYPE DeviceTextType;
1859     USHORT LanguageId;
1860     USHORT DefaultId;
1861     PUSB_STRING_DESCRIPTOR Descriptor;
1862     PWCHAR DeviceText;
1863     UCHAR iProduct = 0;
1864     NTSTATUS Status;
1865     size_t NumSymbols;
1866     size_t Length;
1867 
1868     DPRINT("USBH_PdoQueryDeviceText ... \n");
1869 
1870     DeviceObject = PortExtension->Common.SelfDevice;
1871     IoStack = IoGetCurrentIrpStackLocation(Irp);
1872     DeviceTextType = IoStack->Parameters.QueryDeviceText.DeviceTextType;
1873 
1874     if (DeviceTextType != DeviceTextDescription &&
1875         DeviceTextType != DeviceTextLocationInformation)
1876     {
1877         return Irp->IoStatus.Status;
1878     }
1879 
1880     LanguageId = LANGIDFROMLCID(IoStack->Parameters.QueryDeviceText.LocaleId);
1881     DefaultId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
1882 
1883     if (!LanguageId)
1884     {
1885         LanguageId = DefaultId;
1886     }
1887 
1888     iProduct = PortExtension->DeviceDescriptor.iProduct;
1889 
1890     if (PortExtension->DeviceHandle && iProduct &&
1891         !PortExtension->IgnoringHwSerial &&
1892         !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED))
1893     {
1894         Descriptor = ExAllocatePoolWithTag(NonPagedPool,
1895                                            MAXIMUM_USB_STRING_LENGTH,
1896                                            USB_HUB_TAG);
1897 
1898         if (Descriptor)
1899         {
1900             RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
1901 
1902             for (Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
1903                  ;
1904                  Status = USBH_CheckDeviceLanguage(DeviceObject, DefaultId))
1905             {
1906                 if (NT_SUCCESS(Status))
1907                 {
1908                     Status = USBH_SyncGetStringDescriptor(DeviceObject,
1909                                                           iProduct,
1910                                                           LanguageId,
1911                                                           Descriptor,
1912                                                           MAXIMUM_USB_STRING_LENGTH,
1913                                                           NULL,
1914                                                           TRUE);
1915 
1916                     if (NT_SUCCESS(Status))
1917                     {
1918                         break;
1919                     }
1920                 }
1921 
1922                 if (LanguageId == DefaultId)
1923                 {
1924                     goto Exit;
1925                 }
1926 
1927                 LanguageId = DefaultId;
1928             }
1929 
1930             if (Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
1931             {
1932                 Status = STATUS_UNSUCCESSFUL;
1933             }
1934 
1935             if (NT_SUCCESS(Status))
1936             {
1937                 Length = Descriptor->bLength -
1938                          FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
1939 
1940                 DeviceText = ExAllocatePoolWithTag(PagedPool,
1941                                                    Length + sizeof(UNICODE_NULL),
1942                                                    USB_HUB_TAG);
1943 
1944                 if (DeviceText)
1945                 {
1946                     RtlZeroMemory(DeviceText, Length + sizeof(UNICODE_NULL));
1947 
1948                     RtlCopyMemory(DeviceText, Descriptor->bString, Length);
1949 
1950                     Irp->IoStatus.Information = (ULONG_PTR)DeviceText;
1951 
1952                     DPRINT("USBH_PdoQueryDeviceText: Descriptor->bString - %S\n",
1953                            DeviceText);
1954                 }
1955                 else
1956                 {
1957                     Status = STATUS_INSUFFICIENT_RESOURCES;
1958                 }
1959             }
1960 
1961         Exit:
1962 
1963             ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
1964 
1965             if (NT_SUCCESS(Status))
1966             {
1967                 return Status;
1968             }
1969         }
1970         else
1971         {
1972             Status = STATUS_INSUFFICIENT_RESOURCES;
1973         }
1974     }
1975     else
1976     {
1977         Status = STATUS_NOT_SUPPORTED;
1978     }
1979 
1980     if (!GenericUSBDeviceString)
1981     {
1982         return Status;
1983     }
1984 
1985     NumSymbols = wcslen(GenericUSBDeviceString);
1986     Length = (NumSymbols + 1) * sizeof(WCHAR);
1987 
1988     DeviceText = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
1989 
1990     if (!DeviceText)
1991     {
1992         return STATUS_INSUFFICIENT_RESOURCES;
1993     }
1994 
1995     RtlZeroMemory(DeviceText, Length);
1996 
1997     RtlCopyMemory(DeviceText,
1998                   GenericUSBDeviceString,
1999                   NumSymbols * sizeof(WCHAR));
2000 
2001     Irp->IoStatus.Information = (ULONG_PTR)DeviceText;
2002 
2003     return STATUS_SUCCESS;
2004 }
2005 
2006 NTSTATUS
2007 NTAPI
2008 USBH_SymbolicLink(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2009                   IN const GUID * InterfaceClassGuid,
2010                   IN BOOLEAN IsEnable)
2011 {
2012     NTSTATUS Status = STATUS_SUCCESS;
2013     PVOID NameBuffer;
2014 
2015     DPRINT("USBH_SymbolicLink ... \n");
2016 
2017     if (IsEnable)
2018     {
2019         Status = IoRegisterDeviceInterface(PortExtension->Common.SelfDevice,
2020                                            InterfaceClassGuid,
2021                                            NULL,
2022                                            &PortExtension->SymbolicLinkName);
2023 
2024         if (NT_SUCCESS(Status))
2025         {
2026             USBH_SetPdoRegistryParameter(PortExtension->Common.SelfDevice,
2027                                          L"SymbolicName",
2028                                          PortExtension->SymbolicLinkName.Buffer,
2029                                          PortExtension->SymbolicLinkName.Length,
2030                                          REG_SZ,
2031                                          PLUGPLAY_REGKEY_DEVICE);
2032 
2033             Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName,
2034                                                TRUE);
2035         }
2036     }
2037     else
2038     {
2039         NameBuffer = PortExtension->SymbolicLinkName.Buffer;
2040 
2041         if (NameBuffer)
2042         {
2043             Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName,
2044                                                FALSE);
2045 
2046             ExFreePool(PortExtension->SymbolicLinkName.Buffer);
2047 
2048             PortExtension->SymbolicLinkName.Buffer = NULL;
2049         }
2050     }
2051 
2052     return Status;
2053 }
2054 
2055 NTSTATUS
2056 NTAPI
2057 USBH_RestoreDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2058                    IN BOOLEAN IsKeepDeviceData)
2059 {
2060     PUSBHUB_FDO_EXTENSION HubExtension;
2061     PUSBHUB_PORT_DATA PortData;
2062     NTSTATUS Status;
2063     ULONG ix;
2064 
2065     DPRINT("USBH_RestoreDevice ... \n");
2066 
2067     HubExtension = PortExtension->HubExtension;
2068 
2069     if (!HubExtension)
2070     {
2071         Status = STATUS_UNSUCCESSFUL;
2072         return Status;
2073     }
2074 
2075     ASSERT(PortExtension->PortNumber > 0);
2076     PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
2077 
2078     if (PortExtension->Common.SelfDevice != PortData->DeviceObject)
2079     {
2080         Status = STATUS_UNSUCCESSFUL;
2081         return Status;
2082     }
2083 
2084     Status = USBH_SyncGetPortStatus(HubExtension,
2085                                     PortExtension->PortNumber,
2086                                     &PortData->PortStatus,
2087                                     sizeof(USB_PORT_STATUS_AND_CHANGE));
2088 
2089     if (NT_SUCCESS(Status))
2090     {
2091         for (ix = 0; ix < 3; ix++)
2092         {
2093             Status = USBH_ResetDevice((PUSBHUB_FDO_EXTENSION)HubExtension,
2094                                       PortExtension->PortNumber,
2095                                       IsKeepDeviceData,
2096                                       ix == 0);
2097 
2098             if (NT_SUCCESS(Status) || Status == STATUS_NO_SUCH_DEVICE)
2099             {
2100                 break;
2101             }
2102 
2103             USBH_Wait(1000);
2104         }
2105     }
2106 
2107     PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D3;
2108 
2109     if (NT_SUCCESS(Status))
2110     {
2111         PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL;
2112     }
2113     else
2114     {
2115         PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_INIT_PORT_FAILED |
2116                                         USBHUB_PDO_FLAG_PORT_RESTORE_FAIL);
2117     }
2118 
2119     return Status;
2120 }
2121 
2122 NTSTATUS
2123 NTAPI
2124 USBH_PdoStartDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2125                     IN PIRP Irp)
2126 {
2127     PUSBHUB_FDO_EXTENSION HubExtension;
2128     const GUID * Guid;
2129     NTSTATUS Status;
2130 
2131     DPRINT("USBH_PdoStartDevice: PortExtension - %p\n", PortExtension);
2132 
2133     if (!PortExtension->HubExtension &&
2134         PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
2135     {
2136         PortExtension->HubExtension = PortExtension->RootHubExtension;
2137     }
2138 
2139     HubExtension = PortExtension->HubExtension;
2140 
2141     if (HubExtension)
2142     {
2143         USBHUB_SetDeviceHandleData(HubExtension,
2144                                    PortExtension->Common.SelfDevice,
2145                                    PortExtension->DeviceHandle);
2146     }
2147 
2148     if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE)
2149     {
2150         Guid = &GUID_DEVINTERFACE_USB_HUB;
2151     }
2152     else
2153     {
2154         Guid = &GUID_DEVINTERFACE_USB_DEVICE;
2155     }
2156 
2157     Status = USBH_SymbolicLink(PortExtension, Guid, TRUE);
2158 
2159     if (NT_SUCCESS(Status))
2160     {
2161         PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
2162     }
2163 
2164     if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
2165     {
2166         Status = USBH_RestoreDevice(PortExtension, 0);
2167     }
2168 
2169     PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DEVICE_STARTED;
2170 
2171     PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
2172 
2173     DPRINT1("USBH_PdoStartDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
2174 
2175     return Status;
2176 }
2177 
2178 NTSTATUS
2179 NTAPI
2180 USBH_PdoRemoveDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2181                      IN PUSBHUB_FDO_EXTENSION HubExtension)
2182 {
2183     NTSTATUS Status = STATUS_SUCCESS;
2184     PDEVICE_OBJECT PortDevice;
2185     PUSBHUB_PORT_PDO_EXTENSION PortExt;
2186     PUSBHUB_PORT_DATA PortData;
2187     PIRP IdleNotificationIrp;
2188     PIRP WakeIrp;
2189     PVOID DeviceHandle;
2190     PDEVICE_OBJECT Pdo;
2191     PVOID SerialNumber;
2192     USHORT Port;
2193     KIRQL Irql;
2194 
2195     DPRINT("USBH_PdoRemoveDevice ... \n");
2196 
2197     PortDevice = PortExtension->Common.SelfDevice;
2198     PortExtension->HubExtension = NULL;
2199 
2200     Port = PortExtension->PortNumber;
2201     ASSERT(Port > 0);
2202 
2203     if (HubExtension &&
2204         HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
2205         (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) != 0)
2206     {
2207         USBH_HubSetD0(HubExtension);
2208     }
2209 
2210     IoAcquireCancelSpinLock(&Irql);
2211     IdleNotificationIrp = PortExtension->IdleNotificationIrp;
2212 
2213     if (IdleNotificationIrp)
2214     {
2215         PortExtension->IdleNotificationIrp = NULL;
2216         PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
2217 
2218         if (IdleNotificationIrp->Cancel)
2219         {
2220             IdleNotificationIrp = NULL;
2221         }
2222 
2223         if (IdleNotificationIrp)
2224         {
2225             IoSetCancelRoutine(IdleNotificationIrp, NULL);
2226         }
2227     }
2228 
2229     WakeIrp = PortExtension->PdoWaitWakeIrp;
2230 
2231     if (WakeIrp)
2232     {
2233         PortExtension->PdoWaitWakeIrp = NULL;
2234         PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE;
2235 
2236         if (WakeIrp->Cancel || !IoSetCancelRoutine(WakeIrp, NULL))
2237         {
2238             WakeIrp = NULL;
2239 
2240             ASSERT(HubExtension);
2241             if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
2242             {
2243                 KeSetEvent(&HubExtension->PendingRequestEvent,
2244                            EVENT_INCREMENT,
2245                            FALSE);
2246             }
2247         }
2248     }
2249 
2250     IoReleaseCancelSpinLock(Irql);
2251 
2252     if (IdleNotificationIrp)
2253     {
2254         IdleNotificationIrp->IoStatus.Status = STATUS_CANCELLED;
2255         IoCompleteRequest(IdleNotificationIrp, IO_NO_INCREMENT);
2256     }
2257 
2258     if (WakeIrp)
2259     {
2260         ASSERT(HubExtension);
2261         USBH_CompletePowerIrp(HubExtension, WakeIrp, STATUS_CANCELLED);
2262     }
2263 
2264     PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3;
2265 
2266     if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)
2267     {
2268         Status = USBH_SymbolicLink(PortExtension, NULL, FALSE);
2269 
2270         if (NT_SUCCESS(Status))
2271         {
2272             PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
2273         }
2274     }
2275 
2276     DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
2277                                               NULL);
2278 
2279     if (DeviceHandle)
2280     {
2281         ASSERT(HubExtension);
2282         Status = USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
2283 
2284         if (HubExtension->PortData &&
2285             HubExtension->PortData[Port - 1].DeviceObject == PortDevice)
2286         {
2287             USBH_SyncDisablePort(HubExtension, Port);
2288         }
2289     }
2290 
2291     if (NT_SUCCESS(Status))
2292     {
2293         PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_DEVICE_STARTED;
2294 
2295         if (HubExtension && HubExtension->PortData)
2296         {
2297             PortData = &HubExtension->PortData[Port - 1];
2298 
2299             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING)
2300             {
2301                 Pdo = PortData->DeviceObject;
2302 
2303                 if (Pdo)
2304                 {
2305                     PortData->DeviceObject = NULL;
2306                     PortData->ConnectionStatus = NoDeviceConnected;
2307 
2308                     if (PdoExt(Pdo)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)
2309                     {
2310                         PortExt = PdoExt(Pdo);
2311 
2312                         InsertTailList(&HubExtension->PdoList,
2313                                        &PortExt->PortLink);
2314                     }
2315                 }
2316             }
2317         }
2318 
2319         if (!(PortExtension->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT) &&
2320             !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED))
2321         {
2322             PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_NOT_CONNECTED;
2323 
2324             SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
2325                                                       NULL);
2326 
2327             if (SerialNumber)
2328             {
2329                 ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
2330             }
2331 
2332             DPRINT1("USBH_PdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
2333 
2334             if (HubExtension)
2335                 USBHUB_FlushAllTransfers(HubExtension);
2336 
2337             IoDeleteDevice(PortDevice);
2338         }
2339     }
2340 
2341     if (HubExtension)
2342     {
2343         DPRINT("USBH_PdoRemoveDevice: call USBH_CheckIdleDeferred()\n");
2344         USBH_CheckIdleDeferred(HubExtension);
2345     }
2346 
2347     return Status;
2348 }
2349 
2350 NTSTATUS
2351 NTAPI
2352 USBH_PdoStopDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2353                    IN PIRP Irp)
2354 {
2355     DPRINT1("USBH_PdoStopDevice: UNIMPLEMENTED. FIXME\n");
2356     DbgBreakPoint();
2357     return STATUS_SUCCESS;
2358 }
2359 
2360 NTSTATUS
2361 NTAPI
2362 USBH_FdoPnP(IN PUSBHUB_FDO_EXTENSION HubExtension,
2363             IN PIRP Irp,
2364             IN UCHAR Minor)
2365 {
2366     NTSTATUS Status;
2367     PIO_STACK_LOCATION IoStack;
2368     DEVICE_RELATION_TYPE RelationsType;
2369     BOOLEAN IsCheckIdle;
2370 
2371     DPRINT_PNP("USBH_FdoPnP: HubExtension - %p, Irp - %p, Minor - %X\n",
2372                HubExtension,
2373                Irp,
2374                Minor);
2375 
2376     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST &&
2377         (Minor == IRP_MN_REMOVE_DEVICE || Minor == IRP_MN_STOP_DEVICE))
2378     {
2379         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED;
2380     }
2381 
2382     KeWaitForSingleObject(&HubExtension->IdleSemaphore,
2383                           Executive,
2384                           KernelMode,
2385                           FALSE,
2386                           NULL);
2387 
2388     DPRINT_PNP("USBH_FdoPnP: HubFlags - %lX\n", HubExtension->HubFlags);
2389 
2390     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_GOING_IDLE)
2391     {
2392         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED;
2393     }
2394 
2395     IoStack = IoGetCurrentIrpStackLocation(Irp);
2396     RelationsType = IoStack->Parameters.QueryDeviceRelations.Type;
2397 
2398     if ((HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0) ||
2399         !(HubExtension->HubFlags & (USBHUB_FDO_FLAG_DEVICE_STOPPED | USBHUB_FDO_FLAG_DEVICE_STARTED)) ||
2400         (Minor == IRP_MN_QUERY_DEVICE_RELATIONS && RelationsType == TargetDeviceRelation))
2401     {
2402         IsCheckIdle = FALSE;
2403     }
2404     else
2405     {
2406         DPRINT_PNP("USBH_FdoPnP: IsCheckIdle - TRUE\n");
2407         IsCheckIdle = TRUE;
2408         USBH_HubSetD0(HubExtension);
2409     }
2410 
2411     switch (Minor)
2412     {
2413         case IRP_MN_START_DEVICE:
2414             DPRINT_PNP("FDO IRP_MN_START_DEVICE\n");
2415             IsCheckIdle = FALSE;
2416             Irp->IoStatus.Status = STATUS_SUCCESS;
2417             Status = USBH_FdoStartDevice(HubExtension, Irp);
2418             break;
2419 
2420         case IRP_MN_QUERY_REMOVE_DEVICE:
2421             DPRINT_PNP("FDO IRP_MN_QUERY_REMOVE_DEVICE\n");
2422             Irp->IoStatus.Status = STATUS_SUCCESS;
2423             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2424             break;
2425 
2426         case IRP_MN_REMOVE_DEVICE:
2427             DPRINT_PNP("FDO IRP_MN_REMOVE_DEVICE\n");
2428             IsCheckIdle = FALSE;
2429             HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
2430             Irp->IoStatus.Status = STATUS_SUCCESS;
2431             Status = USBH_FdoRemoveDevice(HubExtension, Irp);
2432             break;
2433 
2434         case IRP_MN_CANCEL_REMOVE_DEVICE:
2435             DPRINT_PNP("FDO IRP_MN_CANCEL_REMOVE_DEVICE\n");
2436             Irp->IoStatus.Status = STATUS_SUCCESS;
2437             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2438             break;
2439 
2440         case IRP_MN_STOP_DEVICE:
2441             DPRINT_PNP("FDO IRP_MN_STOP_DEVICE\n");
2442             IsCheckIdle = FALSE;
2443             Irp->IoStatus.Status = STATUS_SUCCESS;
2444             Status = USBH_FdoStopDevice(HubExtension, Irp);
2445             break;
2446 
2447         case IRP_MN_QUERY_STOP_DEVICE:
2448             DPRINT_PNP("FDO IRP_MN_QUERY_STOP_DEVICE\n");
2449             Irp->IoStatus.Status = STATUS_SUCCESS;
2450             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2451             break;
2452 
2453         case IRP_MN_CANCEL_STOP_DEVICE:
2454             DPRINT_PNP("FDO IRP_MN_CANCEL_STOP_DEVICE\n");
2455             Irp->IoStatus.Status = STATUS_SUCCESS;
2456             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2457             break;
2458 
2459         case IRP_MN_QUERY_DEVICE_RELATIONS:
2460             DPRINT_PNP("FDO IRP_MN_QUERY_DEVICE_RELATIONS\n");
2461 
2462             if (RelationsType != BusRelations)
2463             {
2464                 Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2465                 break;
2466             }
2467 
2468             HubExtension->HubFlags |= USBHUB_FDO_FLAG_HUB_BUSY;
2469 
2470             IsCheckIdle = TRUE;
2471             DPRINT_PNP("USBH_FdoPnP: IsCheckIdle - TRUE\n");
2472 
2473             Status = USBH_FdoQueryBusRelations(HubExtension, Irp);
2474 
2475             HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HUB_BUSY;
2476             break;
2477 
2478         case IRP_MN_QUERY_INTERFACE:
2479             DPRINT_PNP("FDO IRP_MN_QUERY_INTERFACE\n");
2480             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2481             break;
2482 
2483         case IRP_MN_QUERY_CAPABILITIES:
2484             DPRINT_PNP("FDO IRP_MN_QUERY_CAPABILITIES\n");
2485             IoCopyCurrentIrpStackLocationToNext(Irp);
2486 
2487             IoSetCompletionRoutine(Irp,
2488                                    USBH_QueryCapsComplete,
2489                                    HubExtension,
2490                                    TRUE,
2491                                    FALSE,
2492                                    FALSE);
2493 
2494             Status = IoCallDriver(HubExtension->LowerDevice, Irp);
2495             break;
2496 
2497         case IRP_MN_QUERY_RESOURCES:
2498             DPRINT_PNP("FDO IRP_MN_QUERY_RESOURCES\n");
2499             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2500             break;
2501 
2502         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
2503             DPRINT_PNP("FDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
2504             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2505             break;
2506 
2507         case IRP_MN_QUERY_DEVICE_TEXT:
2508             DPRINT_PNP("FDO IRP_MN_QUERY_DEVICE_TEXT\n");
2509             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2510             break;
2511 
2512         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
2513             DPRINT_PNP("FDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
2514             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2515             break;
2516 
2517         case IRP_MN_READ_CONFIG:
2518             DPRINT_PNP("FDO IRP_MN_READ_CONFIG\n");
2519             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2520             break;
2521 
2522         case IRP_MN_WRITE_CONFIG:
2523             DPRINT_PNP("FDO IRP_MN_WRITE_CONFIG\n");
2524             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2525             break;
2526 
2527         case IRP_MN_EJECT:
2528             DPRINT_PNP("FDO IRP_MN_EJECT\n");
2529             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2530             break;
2531 
2532         case IRP_MN_SET_LOCK:
2533             DPRINT_PNP("FDO IRP_MN_SET_LOCK\n");
2534             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2535             break;
2536 
2537         case IRP_MN_QUERY_ID:
2538             DPRINT_PNP("FDO IRP_MN_QUERY_ID\n");
2539             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2540             break;
2541 
2542         case IRP_MN_QUERY_PNP_DEVICE_STATE:
2543             DPRINT_PNP("FDO IRP_MN_QUERY_PNP_DEVICE_STATE\n");
2544 
2545             if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
2546             {
2547                 Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
2548             }
2549 
2550             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2551             break;
2552 
2553         case IRP_MN_QUERY_BUS_INFORMATION:
2554             DPRINT_PNP("FDO IRP_MN_QUERY_BUS_INFORMATION\n");
2555             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2556             break;
2557 
2558         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
2559             DPRINT_PNP("FDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
2560             Irp->IoStatus.Status = STATUS_SUCCESS;
2561             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2562             break;
2563 
2564         case IRP_MN_SURPRISE_REMOVAL:
2565             DPRINT_PNP("FDO IRP_MN_SURPRISE_REMOVAL\n");
2566             USBH_FdoSurpriseRemoveDevice(HubExtension, Irp);
2567             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2568             break;
2569 
2570         default:
2571             DPRINT_PNP("FDO unknown IRP_MN_???\n");
2572             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
2573             break;
2574     }
2575 
2576     KeReleaseSemaphore(&HubExtension->IdleSemaphore,
2577                        LOW_REALTIME_PRIORITY,
2578                        1,
2579                        FALSE);
2580 
2581     if (IsCheckIdle)
2582     {
2583         DPRINT_PNP("USBH_FdoPnP: call USBH_CheckIdleDeferred()\n");
2584         USBH_CheckIdleDeferred(HubExtension);
2585     }
2586 
2587     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_STATE_CHANGING;
2588 
2589     return Status;
2590 }
2591 
2592 NTSTATUS
2593 NTAPI
2594 USBH_PdoPnP(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2595             IN PIRP Irp,
2596             IN UCHAR Minor,
2597             OUT BOOLEAN * IsCompleteIrp)
2598 {
2599     NTSTATUS Status;
2600     PIO_STACK_LOCATION IoStack;
2601     PPNP_BUS_INFORMATION BusInfo;
2602     PDEVICE_CAPABILITIES DeviceCapabilities;
2603     USHORT Size;
2604     USHORT Version;
2605     PUSBHUB_FDO_EXTENSION HubExtension;
2606     PDEVICE_RELATIONS DeviceRelation;
2607 
2608     DPRINT_PNP("USBH_PdoPnP: PortExtension - %p, Irp - %p, Minor - %X\n",
2609                PortExtension,
2610                Irp,
2611                Minor);
2612 
2613     IoStack = IoGetCurrentIrpStackLocation(Irp);
2614 
2615     *IsCompleteIrp = TRUE;
2616 
2617     switch (Minor)
2618     {
2619         case IRP_MN_START_DEVICE:
2620             DPRINT_PNP("PDO IRP_MN_START_DEVICE\n");
2621             return USBH_PdoStartDevice(PortExtension, Irp);
2622 
2623         case IRP_MN_QUERY_REMOVE_DEVICE:
2624             DPRINT_PNP("PDO IRP_MN_QUERY_REMOVE_DEVICE\n");
2625             return STATUS_SUCCESS;
2626 
2627         case IRP_MN_REMOVE_DEVICE:
2628             DPRINT_PNP("PDO IRP_MN_REMOVE_DEVICE\n");
2629             return USBH_PdoRemoveDevice(PortExtension, PortExtension->HubExtension);
2630 
2631         case IRP_MN_CANCEL_REMOVE_DEVICE:
2632             DPRINT_PNP("PDO IRP_MN_CANCEL_REMOVE_DEVICE\n");
2633             return STATUS_SUCCESS;
2634 
2635         case IRP_MN_STOP_DEVICE:
2636             DPRINT_PNP("PDO IRP_MN_STOP_DEVICE\n");
2637             return USBH_PdoStopDevice(PortExtension, Irp);
2638 
2639         case IRP_MN_QUERY_STOP_DEVICE:
2640             DPRINT_PNP("PDO IRP_MN_QUERY_STOP_DEVICE\n");
2641             return STATUS_SUCCESS;
2642 
2643         case IRP_MN_CANCEL_STOP_DEVICE:
2644             DPRINT_PNP("PDO IRP_MN_CANCEL_STOP_DEVICE\n");
2645             return STATUS_SUCCESS;
2646 
2647         case IRP_MN_QUERY_DEVICE_RELATIONS:
2648             DPRINT_PNP("PDO IRP_MN_QUERY_DEVICE_RELATIONS\n");
2649 
2650             if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
2651             {
2652                 return Irp->IoStatus.Status;
2653             }
2654 
2655             DeviceRelation = ExAllocatePoolWithTag(PagedPool,
2656                                                    sizeof(DEVICE_RELATIONS),
2657                                                    USB_HUB_TAG);
2658 
2659             if (DeviceRelation)
2660             {
2661                 RtlZeroMemory(DeviceRelation, sizeof(DEVICE_RELATIONS));
2662 
2663                 DeviceRelation->Count = 1;
2664                 DeviceRelation->Objects[0] = PortExtension->Common.SelfDevice;
2665 
2666                 ObReferenceObject(DeviceRelation->Objects[0]);
2667 
2668                 Status = STATUS_SUCCESS;
2669             }
2670             else
2671             {
2672                 Status = STATUS_INSUFFICIENT_RESOURCES;
2673             }
2674 
2675             Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
2676             break;
2677 
2678         case IRP_MN_QUERY_INTERFACE:
2679             DPRINT_PNP("PDO IRP_MN_QUERY_INTERFACE\n");
2680 
2681             *IsCompleteIrp = 0;
2682 
2683             if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
2684                                    &USB_BUS_INTERFACE_USBDI_GUID))
2685             {
2686                 IoStack->Parameters.QueryInterface.InterfaceSpecificData = PortExtension->DeviceHandle;
2687             }
2688 
2689             HubExtension = PortExtension->HubExtension;
2690 
2691             if (!HubExtension)
2692             {
2693                 HubExtension = PortExtension->RootHubExtension;
2694             }
2695 
2696             Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp);
2697             break;
2698 
2699         case IRP_MN_QUERY_CAPABILITIES:
2700             DPRINT_PNP("PDO IRP_MN_QUERY_CAPABILITIES\n");
2701 
2702             DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
2703 
2704             Size = DeviceCapabilities->Size;
2705             Version = DeviceCapabilities->Version;
2706 
2707             RtlCopyMemory(DeviceCapabilities,
2708                           &PortExtension->Capabilities,
2709                           sizeof(DEVICE_CAPABILITIES));
2710 
2711             DeviceCapabilities->Size = Size;
2712             DeviceCapabilities->Version = Version;
2713 
2714             /* All devices connected to a hub are removable */
2715             DeviceCapabilities->Removable = 1;
2716 
2717             Status = STATUS_SUCCESS;
2718             break;
2719 
2720         case IRP_MN_QUERY_RESOURCES:
2721             DPRINT_PNP("PDO IRP_MN_QUERY_RESOURCES\n");
2722             Status = Irp->IoStatus.Status;
2723             break;
2724 
2725         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
2726             DPRINT_PNP("PDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
2727             PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_ENUMERATED;
2728 
2729             /* FIXME HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Enum\USB\
2730                Vid_????&Pid_????\????????????\Device Parameters\
2731                if (ExtPropDescSemaphore)
2732             */
2733 
2734             Status = STATUS_SUCCESS;
2735             break;
2736 
2737         case IRP_MN_QUERY_DEVICE_TEXT:
2738             DPRINT_PNP("PDO IRP_MN_QUERY_DEVICE_TEXT\n");
2739             return USBH_PdoQueryDeviceText(PortExtension, Irp);
2740 
2741         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
2742             DPRINT_PNP("PDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
2743             Status = Irp->IoStatus.Status;
2744             break;
2745 
2746         case IRP_MN_READ_CONFIG:
2747             DPRINT_PNP("PDO IRP_MN_READ_CONFIG\n");
2748             DbgBreakPoint();
2749             Status = Irp->IoStatus.Status;
2750             break;
2751 
2752         case IRP_MN_WRITE_CONFIG:
2753             DPRINT_PNP("PDO IRP_MN_WRITE_CONFIG\n");
2754             DbgBreakPoint();
2755             Status = Irp->IoStatus.Status;
2756             break;
2757 
2758         case IRP_MN_EJECT:
2759             DPRINT_PNP("PDO IRP_MN_EJECT\n");
2760             DbgBreakPoint();
2761             Status = Irp->IoStatus.Status;
2762             break;
2763 
2764         case IRP_MN_SET_LOCK:
2765             DPRINT_PNP("PDO IRP_MN_SET_LOCK\n");
2766             DbgBreakPoint();
2767             Status = Irp->IoStatus.Status;
2768             break;
2769 
2770         case IRP_MN_QUERY_ID:
2771             DPRINT_PNP("PDO IRP_MN_QUERY_ID\n");
2772             return USBH_PdoQueryId(PortExtension, Irp);
2773 
2774         case IRP_MN_QUERY_PNP_DEVICE_STATE:
2775             DPRINT_PNP("PDO IRP_MN_QUERY_PNP_DEVICE_STATE\n");
2776             if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_INSUFFICIENT_PWR |
2777                                                USBHUB_PDO_FLAG_OVERCURRENT_PORT |
2778                                                USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
2779                                                USBHUB_PDO_FLAG_INIT_PORT_FAILED))
2780             {
2781                 Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
2782             }
2783 
2784             Status = STATUS_SUCCESS;
2785             break;
2786 
2787         case IRP_MN_QUERY_BUS_INFORMATION:
2788             DPRINT_PNP("PDO IRP_MN_QUERY_BUS_INFORMATION\n");
2789 
2790             BusInfo = ExAllocatePoolWithTag(PagedPool,
2791                                             sizeof(PNP_BUS_INFORMATION),
2792                                             USB_HUB_TAG);
2793 
2794             if (!BusInfo)
2795             {
2796                 return STATUS_INSUFFICIENT_RESOURCES;
2797             }
2798 
2799             RtlZeroMemory(BusInfo, sizeof(PNP_BUS_INFORMATION));
2800 
2801             RtlCopyMemory(&BusInfo->BusTypeGuid,
2802                           &GUID_BUS_TYPE_USB,
2803                           sizeof(BusInfo->BusTypeGuid));
2804 
2805             BusInfo->LegacyBusType = PNPBus;
2806             BusInfo->BusNumber = 0;
2807 
2808             Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
2809             Status = STATUS_SUCCESS;
2810             break;
2811 
2812         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
2813             DPRINT_PNP("PDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
2814             DbgBreakPoint();
2815             Status = Irp->IoStatus.Status;
2816             break;
2817 
2818         case IRP_MN_SURPRISE_REMOVAL:
2819             DPRINT_PNP("PDO IRP_MN_SURPRISE_REMOVAL\n");
2820             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)
2821             {
2822                 Status = USBH_SymbolicLink(PortExtension, NULL, FALSE);
2823 
2824                 if (NT_SUCCESS(Status))
2825                 {
2826                     PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
2827                 }
2828             }
2829 
2830             Status = STATUS_SUCCESS;
2831             break;
2832 
2833         default:
2834             DPRINT_PNP("PDO unknown IRP_MN_???\n");
2835             Status = Irp->IoStatus.Status;
2836             break;
2837     }
2838 
2839     return Status;
2840 }
2841