xref: /reactos/drivers/usb/usbhub/ioctl.c (revision 2eb96f0c)
1 /*
2  * PROJECT:     ReactOS USB Hub Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBHub I/O control 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_IOCTL
14 #include "dbg_uhub.h"
15 
16 NTSTATUS
17 NTAPI
18 USBH_SelectConfigOrInterfaceComplete(IN PDEVICE_OBJECT DeviceObject,
19                                      IN PIRP Irp,
20                                      IN PVOID Context)
21 {
22     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
23     PUSBHUB_FDO_EXTENSION HubExtension;
24     PVOID TimeoutContext; // PUSBHUB_BANDWIDTH_TIMEOUT_CONTEXT
25     PUSBHUB_PORT_DATA PortData = NULL;
26     NTSTATUS Status;
27     KIRQL OldIrql;
28     PURB Urb;
29 
30     DPRINT("USBH_SelectConfigOrInterfaceComplete ... \n");
31 
32     if (Irp->PendingReturned)
33     {
34         IoMarkIrpPending(Irp);
35     }
36 
37     PortExtension = Context;
38     HubExtension = PortExtension->HubExtension;
39 
40     ASSERT(PortExtension->PortNumber > 0);
41 
42     if (HubExtension)
43     {
44         PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
45     }
46 
47     Status = Irp->IoStatus.Status;
48 
49     if (NT_SUCCESS(Irp->IoStatus.Status))
50     {
51         KeAcquireSpinLock(&PortExtension->PortTimeoutSpinLock, &OldIrql);
52 
53         TimeoutContext = PortExtension->BndwTimeoutContext;
54 
55         if (TimeoutContext)
56         {
57             DPRINT1("USBH_SelectConfigOrInterfaceComplete: TimeoutContext != NULL. FIXME\n");
58             DbgBreakPoint();
59         }
60 
61         KeReleaseSpinLock(&PortExtension->PortTimeoutSpinLock, OldIrql);
62 
63         PortExtension->PortPdoFlags &= ~(USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
64                                          USBHUB_PDO_FLAG_ALLOC_BNDW_FAILED);
65 
66         if (PortData && PortData->ConnectionStatus != DeviceHubNestedTooDeeply)
67         {
68             PortData->ConnectionStatus = DeviceConnected;
69         }
70     }
71     else
72     {
73         Urb = URB_FROM_IRP(Irp);
74         DPRINT1("USBH_SelectConfigOrInterfaceComplete: Status = 0x%lx, UsbdStatus = 0x%lx\n", Status, Urb->UrbHeader.Status);
75         if (Urb->UrbHeader.Status == USBD_STATUS_NO_BANDWIDTH)
76         {
77             DPRINT1("USBH_SelectConfigOrInterfaceComplete: USBD_STATUS_NO_BANDWIDTH. FIXME\n");
78             DbgBreakPoint();
79         }
80     }
81 
82     return Status;
83 }
84 
85 NTSTATUS
86 NTAPI
87 USBH_PdoUrbFilter(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
88                   IN PIRP Irp)
89 {
90     PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
91     PUSBHUB_FDO_EXTENSION HubExtension;
92     PDEVICE_OBJECT DeviceObject;
93     PURB Urb;
94     USHORT Function;
95     ULONG MaxPower;
96     USBD_STATUS UrbStatus;
97     BOOLEAN IsValidConfig;
98 
99     HubExtension = PortExtension->HubExtension;
100     DeviceObject = PortExtension->Common.SelfDevice;
101 
102     Urb = URB_FROM_IRP(Irp);
103 
104     DPRINT_IOCTL("USBH_PdoUrbFilter: Device - %p, Irp - %p, Urb - %p\n",
105                  DeviceObject,
106                  Irp,
107                  Urb);
108 
109     if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
110                                        USBHUB_PDO_FLAG_PORT_RESSETING))
111     {
112         Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
113         USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
114         return STATUS_INVALID_PARAMETER;
115     }
116 
117     Function = Urb->UrbHeader.Function;
118 
119     switch (Function)
120     {
121         case URB_FUNCTION_SELECT_CONFIGURATION:
122         {
123             ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor;
124 
125             if (ConfigDescriptor)
126             {
127                 IsValidConfig = TRUE;
128 
129                 if (ConfigDescriptor->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE)
130                 {
131                     DPRINT1("USBH_PdoUrbFilter: Not valid Cfg. bDescriptorType\n");
132                     IsValidConfig = FALSE;
133                     UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR;
134                 }
135 
136                 if (ConfigDescriptor->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
137                 {
138                     DPRINT1("USBH_PdoUrbFilter: Size Cfg. descriptor is too small\n");
139                     IsValidConfig = FALSE;
140                     UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR;
141                 }
142 
143                 if (!IsValidConfig)
144                 {
145                     Urb->UrbHeader.Status = UrbStatus;
146                     USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
147                     return STATUS_INVALID_PARAMETER;
148                 }
149 
150                 MaxPower = 2 * ConfigDescriptor->MaxPower;
151                 PortExtension->MaxPower = MaxPower;
152 
153                 if (HubExtension->MaxPowerPerPort < MaxPower)
154                 {
155                     PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INSUFFICIENT_PWR;
156 
157                     DPRINT1("USBH_PdoUrbFilter: USBH_InvalidatePortDeviceState() UNIMPLEMENTED. FIXME\n");
158                     DbgBreakPoint();
159 
160                     USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
161                     return STATUS_INVALID_PARAMETER;
162                 }
163             }
164         }
165 
166         /* fall through */
167 
168         case URB_FUNCTION_SELECT_INTERFACE:
169         {
170             IoCopyCurrentIrpStackLocationToNext(Irp);
171 
172             IoSetCompletionRoutine(Irp,
173                                    USBH_SelectConfigOrInterfaceComplete,
174                                    PortExtension,
175                                    TRUE,
176                                    TRUE,
177                                    TRUE);
178 
179             return IoCallDriver(HubExtension->RootHubPdo2, Irp);
180         }
181 
182         case URB_FUNCTION_CONTROL_TRANSFER:
183         case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
184         case URB_FUNCTION_ISOCH_TRANSFER:
185         {
186             if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING)
187             {
188                 Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
189                 USBH_CompleteIrp(Irp, STATUS_DELETE_PENDING);
190                 return STATUS_DELETE_PENDING;
191             }
192 
193             break;
194         }
195 
196         case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR:
197             DPRINT1("USBH_PdoUrbFilter: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR UNIMPLEMENTED. FIXME\n");
198             USBH_CompleteIrp(Irp, STATUS_NOT_IMPLEMENTED);
199             return STATUS_NOT_IMPLEMENTED;
200 
201         default:
202             break;
203     }
204 
205     return USBH_PassIrp(HubExtension->RootHubPdo2, Irp);
206 }
207 
208 NTSTATUS
209 NTAPI
210 USBH_PdoIoctlSubmitUrb(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
211                        IN PIRP Irp)
212 {
213     PUSBHUB_FDO_EXTENSION HubExtension;
214     PURB Urb;
215     NTSTATUS Status;
216 
217     DPRINT_IOCTL("USBH_PdoIoctlSubmitUrb ... \n");
218 
219     HubExtension = PortExtension->HubExtension;
220 
221     Urb = URB_FROM_IRP(Irp);
222 
223     if (PortExtension->DeviceHandle == NULL)
224     {
225         Urb->UrbHeader.UsbdDeviceHandle = NULL;
226         Status = USBH_PassIrp(HubExtension->RootHubPdo2, Irp);
227     }
228     else
229     {
230         Urb->UrbHeader.UsbdDeviceHandle = PortExtension->DeviceHandle;
231         Status = USBH_PdoUrbFilter(PortExtension, Irp);
232     }
233 
234     return Status;
235 }
236 
237 NTSTATUS
238 NTAPI
239 USBH_PdoIoctlGetPortStatus(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
240                            IN PIRP Irp)
241 {
242     PUSBHUB_FDO_EXTENSION HubExtension;
243     PUSBHUB_PORT_DATA PortData;
244     PIO_STACK_LOCATION IoStack;
245     PULONG PortStatus;
246     NTSTATUS Status;
247 
248     DPRINT("USBH_PdoIoctlGetPortStatus ... \n");
249 
250     HubExtension = PortExtension->HubExtension;
251 
252     InterlockedIncrement(&HubExtension->PendingRequestCount);
253 
254     KeWaitForSingleObject(&HubExtension->HubSemaphore,
255                           Executive,
256                           KernelMode,
257                           FALSE,
258                           NULL);
259 
260     ASSERT(PortExtension->PortNumber > 0);
261     PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
262 
263     Status = USBH_SyncGetPortStatus(HubExtension,
264                                     PortExtension->PortNumber,
265                                     &PortData->PortStatus,
266                                     sizeof(USB_PORT_STATUS_AND_CHANGE));
267 
268     IoStack = IoGetCurrentIrpStackLocation(Irp);
269     PortStatus = IoStack->Parameters.Others.Argument1;
270 
271     *PortStatus = 0;
272 
273     if (PortExtension->Common.SelfDevice == PortData->DeviceObject)
274     {
275         if (PortData->PortStatus.PortStatus.Usb20PortStatus.PortEnabledDisabled)
276         {
277             *PortStatus |= USBD_PORT_ENABLED;
278         }
279 
280         if (PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
281         {
282             *PortStatus |= USBD_PORT_CONNECTED;
283         }
284     }
285 
286     KeReleaseSemaphore(&HubExtension->HubSemaphore,
287                        LOW_REALTIME_PRIORITY,
288                        1,
289                        FALSE);
290 
291     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
292     {
293         KeSetEvent(&HubExtension->PendingRequestEvent,
294                    EVENT_INCREMENT,
295                    FALSE);
296     }
297 
298     USBH_CompleteIrp(Irp, Status);
299 
300     return Status;
301 }
302 
303 VOID
304 NTAPI
305 USBH_ResetPortWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
306                      IN PVOID Context)
307 {
308     PUSBHUB_RESET_PORT_CONTEXT WorkItemReset;
309     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
310     PUSB_DEVICE_HANDLE DeviceHandle;
311     NTSTATUS Status;
312     USHORT Port;
313 
314     DPRINT("USBH_ResetPortWorker ... \n");
315 
316     WorkItemReset = Context;
317 
318     PortExtension = WorkItemReset->PortExtension;
319 
320     if (!HubExtension)
321     {
322         Status = STATUS_UNSUCCESSFUL;
323         goto Exit;
324     }
325 
326     InterlockedIncrement(&HubExtension->PendingRequestCount);
327 
328     KeWaitForSingleObject(&HubExtension->HubSemaphore,
329                           Executive,
330                           KernelMode,
331                           FALSE,
332                           NULL);
333 
334     Port = PortExtension->PortNumber;
335     DeviceHandle = PortExtension->DeviceHandle;
336 
337     ASSERT(Port > 0);
338 
339     if (PortExtension->Common.SelfDevice == HubExtension->PortData[Port-1].DeviceObject &&
340         DeviceHandle != NULL)
341     {
342         USBD_RemoveDeviceEx(HubExtension,
343                             DeviceHandle,
344                             USBD_MARK_DEVICE_BUSY);
345 
346         Status = USBH_ResetDevice(HubExtension,
347                                   Port,
348                                   TRUE,
349                                   FALSE);
350     }
351     else
352     {
353         Status = STATUS_INVALID_PARAMETER;
354     }
355 
356     KeReleaseSemaphore(&HubExtension->HubSemaphore,
357                        LOW_REALTIME_PRIORITY,
358                        1,
359                        FALSE);
360 
361     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
362     {
363         KeSetEvent(&HubExtension->PendingRequestEvent,
364                    EVENT_INCREMENT,
365                    FALSE);
366     }
367 
368 Exit:
369 
370     PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESSETING;
371 
372     USBH_CompleteIrp(WorkItemReset->Irp, Status);
373 
374     WorkItemReset->PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL;
375 }
376 
377 NTSTATUS
378 NTAPI
379 USBH_PdoIoctlResetPort(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
380                        IN PIRP Irp)
381 {
382     PUSBHUB_FDO_EXTENSION HubExtension;
383     PUSBHUB_RESET_PORT_CONTEXT HubWorkItemBuffer;
384     PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
385     NTSTATUS Status;
386 
387     HubExtension = PortExtension->HubExtension;
388 
389     DPRINT("USBH_PdoIoctlResetPort ... \n");
390 
391     if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_RESSETING)
392     {
393         Status = STATUS_UNSUCCESSFUL;
394         USBH_CompleteIrp(Irp, Status);
395         return Status;
396     }
397 
398     Status = USBH_AllocateWorkItem(HubExtension,
399                                    &HubIoWorkItem,
400                                    USBH_ResetPortWorker,
401                                    sizeof(USBHUB_RESET_PORT_CONTEXT),
402                                    (PVOID *)&HubWorkItemBuffer,
403                                    DelayedWorkQueue);
404 
405     if (!NT_SUCCESS(Status))
406     {
407         Status = STATUS_UNSUCCESSFUL;
408         USBH_CompleteIrp(Irp, Status);
409         return Status;
410     }
411 
412     PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_PORT_RESSETING;
413     IoMarkIrpPending(Irp);
414 
415     HubWorkItemBuffer->PortExtension = PortExtension;
416     HubWorkItemBuffer->Irp = Irp;
417 
418     Status = STATUS_PENDING;
419 
420     USBH_QueueWorkItem(PortExtension->HubExtension, HubIoWorkItem);
421 
422     return Status;
423 }
424 
425 VOID
426 NTAPI
427 USBH_PortIdleNotificationCancelRoutine(IN PDEVICE_OBJECT Device,
428                                        IN PIRP Irp)
429 {
430     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
431     PUSBHUB_FDO_EXTENSION HubExtension;
432     PIRP PendingIdleIrp = NULL;
433     PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
434     PUSBHUB_IDLE_PORT_CANCEL_CONTEXT HubWorkItemBuffer;
435     NTSTATUS Status;
436 
437     DPRINT("USBH_PortIdleNotificationCancelRoutine ... \n");
438 
439     PortExtension = Device->DeviceExtension;
440     PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
441 
442     HubExtension = PortExtension->HubExtension;
443     ASSERT(HubExtension);
444 
445     PortExtension->IdleNotificationIrp = NULL;
446 
447     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
448     {
449         PendingIdleIrp = HubExtension->PendingIdleIrp;
450         HubExtension->PendingIdleIrp = NULL;
451     }
452 
453     IoReleaseCancelSpinLock(Irp->CancelIrql);
454 
455     if (PendingIdleIrp)
456     {
457         USBH_HubCancelIdleIrp(HubExtension, PendingIdleIrp);
458     }
459 
460     if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
461     {
462         goto ErrorExit;
463     }
464 
465     Status = USBH_AllocateWorkItem(HubExtension,
466                                    &HubIoWorkItem,
467                                    USBH_IdleCancelPowerHubWorker,
468                                    sizeof(USBHUB_IDLE_PORT_CANCEL_CONTEXT),
469                                    (PVOID *)&HubWorkItemBuffer,
470                                    DelayedWorkQueue);
471 
472     if (NT_SUCCESS(Status))
473     {
474         HubWorkItemBuffer->Irp = Irp;
475         USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
476         return;
477     }
478 
479 ErrorExit:
480 
481     Irp->IoStatus.Status = STATUS_CANCELLED;
482     IoCompleteRequest(Irp, IO_NO_INCREMENT);
483 }
484 
485 NTSTATUS
486 NTAPI
487 USBH_PortIdleNotificationRequest(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
488                                  IN PIRP Irp)
489 {
490     PUSBHUB_FDO_EXTENSION HubExtension;
491     PIO_STACK_LOCATION IoStack;
492     PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo;
493     NTSTATUS Status;
494     KIRQL Irql;
495 
496     DPRINT("USBH_PortIdleNotificationRequest ... \n");
497 
498     HubExtension = PortExtension->HubExtension;
499 
500     IoAcquireCancelSpinLock(&Irql);
501 
502     if (PortExtension->IdleNotificationIrp)
503     {
504         IoReleaseCancelSpinLock(Irql);
505         Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
506         IoCompleteRequest(Irp, IO_NO_INCREMENT);
507         return STATUS_DEVICE_BUSY;
508     }
509 
510     IoStack = IoGetCurrentIrpStackLocation(Irp);
511     IdleCallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
512 
513     if (!IdleCallbackInfo || !IdleCallbackInfo->IdleCallback)
514     {
515         IoReleaseCancelSpinLock(Irql);
516 
517         Status = STATUS_NO_CALLBACK_ACTIVE;
518         Irp->IoStatus.Status = Status;
519         IoCompleteRequest(Irp, IO_NO_INCREMENT);
520 
521         return Status;
522     }
523 
524     IoSetCancelRoutine(Irp, USBH_PortIdleNotificationCancelRoutine);
525 
526     if (Irp->Cancel)
527     {
528         if (IoSetCancelRoutine(Irp, NULL))
529         {
530             IoReleaseCancelSpinLock(Irql);
531             Status = STATUS_CANCELLED;
532             Irp->IoStatus.Status = STATUS_CANCELLED;
533             IoCompleteRequest(Irp, IO_NO_INCREMENT);
534         }
535         else
536         {
537             IoMarkIrpPending(Irp);
538             IoReleaseCancelSpinLock(Irql);
539             Status = STATUS_PENDING;
540         }
541     }
542     else
543     {
544         PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
545 
546         PortExtension->IdleNotificationIrp = Irp;
547         IoMarkIrpPending(Irp);
548 
549         IoReleaseCancelSpinLock(Irql);
550         Status = STATUS_PENDING;
551 
552         DPRINT("USBH_PortIdleNotificationRequest: IdleNotificationIrp - %p\n",
553                PortExtension->IdleNotificationIrp);
554 
555         USBH_CheckIdleDeferred(HubExtension);
556     }
557 
558     return Status;
559 }
560 
561 NTSTATUS
562 NTAPI
563 USBH_IoctlGetNodeName(IN PUSBHUB_FDO_EXTENSION HubExtension,
564                       IN PIRP Irp)
565 {
566     PUSB_NODE_CONNECTION_NAME ConnectionName;
567     PDEVICE_OBJECT PortDevice;
568     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
569     size_t LengthSkip;
570     PWCHAR Buffer;
571     ULONG BufferLength;
572     PWCHAR BufferEnd;
573     ULONG_PTR LengthReturned;
574     size_t LengthName;
575     ULONG Length;
576     NTSTATUS Status;
577     PIO_STACK_LOCATION IoStack;
578     ULONG_PTR Information;
579 
580     DPRINT("USBH_IoctlGetNodeName ... \n");
581 
582     Status = STATUS_SUCCESS;
583 
584     ConnectionName = Irp->AssociatedIrp.SystemBuffer;
585 
586     IoStack = IoGetCurrentIrpStackLocation(Irp);
587     Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
588 
589     if (Length < sizeof(USB_NODE_CONNECTION_NAME))
590     {
591         Status = STATUS_BUFFER_TOO_SMALL;
592         Information = Irp->IoStatus.Information;
593         goto Exit;
594     }
595 
596     if (ConnectionName->ConnectionIndex == 0 ||
597         ConnectionName->ConnectionIndex > HubExtension->HubDescriptor->bNumberOfPorts)
598     {
599         Status = STATUS_INVALID_PARAMETER;
600         Information = Irp->IoStatus.Information;
601         goto Exit;
602     }
603 
604     PortDevice = HubExtension->PortData[ConnectionName->ConnectionIndex - 1].DeviceObject;
605 
606     if (!PortDevice)
607     {
608         ConnectionName->NodeName[0] = 0;
609         ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME);
610 
611         Information = sizeof(USB_NODE_CONNECTION_NAME);
612         goto Exit;
613     }
614 
615     PortExtension = PortDevice->DeviceExtension;
616 
617     if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE) ||
618         !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DEVICE_STARTED) ||
619         !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE))
620     {
621         ConnectionName->NodeName[0] = 0;
622         ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME);
623 
624         Information = sizeof(USB_NODE_CONNECTION_NAME);
625         goto Exit;
626     }
627 
628     Buffer = PortExtension->SymbolicLinkName.Buffer;
629     BufferLength = PortExtension->SymbolicLinkName.Length;
630 
631     ASSERT(Buffer[BufferLength / sizeof(WCHAR)] == UNICODE_NULL);
632 
633     LengthSkip = 0;
634 
635     if (*Buffer == L'\\')
636     {
637         BufferEnd = wcschr(Buffer + 1, L'\\');
638 
639         if (BufferEnd != NULL)
640         {
641             LengthSkip = (BufferEnd + 1 - Buffer) * sizeof(WCHAR);
642         }
643         else
644         {
645             LengthSkip = PortExtension->SymbolicLinkName.Length;
646         }
647     }
648 
649     LengthName = BufferLength - LengthSkip;
650 
651     ConnectionName->ActualLength = 0;
652 
653     RtlZeroMemory(ConnectionName->NodeName,
654                   Length - FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName));
655 
656     LengthReturned = sizeof(USB_NODE_CONNECTION_NAME) + LengthName;
657 
658     if (Length < LengthReturned)
659     {
660         ConnectionName->NodeName[0] = 0;
661         ConnectionName->ActualLength = LengthReturned;
662 
663         Information = sizeof(USB_NODE_CONNECTION_NAME);
664         goto Exit;
665     }
666 
667     RtlCopyMemory(&ConnectionName->NodeName[0],
668                   &Buffer[LengthSkip / sizeof(WCHAR)],
669                   LengthName);
670 
671     ConnectionName->ActualLength = LengthReturned;
672 
673     Status = STATUS_SUCCESS;
674     Information = LengthReturned;
675 
676 Exit:
677     Irp->IoStatus.Information = Information;
678     USBH_CompleteIrp(Irp, Status);
679     return Status;
680 }
681 
682 NTSTATUS
683 NTAPI
684 USBH_IoctlGetNodeInformation(IN PUSBHUB_FDO_EXTENSION HubExtension,
685                              IN PIRP Irp)
686 {
687     PUSB_NODE_INFORMATION NodeInfo;
688     PIO_STACK_LOCATION IoStack;
689     ULONG BufferLength;
690     NTSTATUS Status;
691     BOOLEAN HubIsBusPowered;
692 
693     DPRINT("USBH_IoctlGetNodeInformation ... \n");
694 
695     Status = STATUS_SUCCESS;
696 
697     NodeInfo = Irp->AssociatedIrp.SystemBuffer;
698 
699     IoStack = IoGetCurrentIrpStackLocation(Irp);
700     BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
701 
702     RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, BufferLength);
703 
704     if (BufferLength < sizeof(USB_NODE_INFORMATION))
705     {
706         Status = STATUS_BUFFER_TOO_SMALL;
707         USBH_CompleteIrp(Irp, Status);
708         return Status;
709     }
710 
711     NodeInfo->NodeType = UsbHub;
712 
713     RtlCopyMemory(&NodeInfo->u.HubInformation.HubDescriptor,
714                   HubExtension->HubDescriptor,
715                   sizeof(USB_HUB_DESCRIPTOR));
716 
717     HubIsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice,
718                                            HubExtension->HubConfigDescriptor);
719 
720     NodeInfo->u.HubInformation.HubIsBusPowered = HubIsBusPowered;
721 
722     Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
723 
724     USBH_CompleteIrp(Irp, Status);
725 
726     return Status;
727 }
728 
729 NTSTATUS
730 NTAPI
731 USBH_IoctlGetHubCapabilities(IN PUSBHUB_FDO_EXTENSION HubExtension,
732                              IN PIRP Irp)
733 {
734     PUSB_HUB_CAPABILITIES Capabilities;
735     PIO_STACK_LOCATION IoStack;
736     ULONG BufferLength;
737     ULONG Length;
738     USB_HUB_CAPABILITIES HubCaps;
739 
740     DPRINT("USBH_IoctlGetHubCapabilities ... \n");
741 
742     Capabilities = Irp->AssociatedIrp.SystemBuffer;
743 
744     HubCaps.HubIs2xCapable = (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB) ==
745                               USBHUB_FDO_FLAG_USB20_HUB;
746 
747     IoStack = IoGetCurrentIrpStackLocation(Irp);
748 
749     BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
750 
751     if (BufferLength == 0)
752     {
753         Irp->IoStatus.Information = BufferLength;
754         USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
755         return STATUS_INVALID_PARAMETER;
756     }
757 
758     if (BufferLength <= sizeof(HubCaps))
759     {
760         Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
761     }
762     else
763     {
764         Length = sizeof(HubCaps);
765     }
766 
767     RtlZeroMemory(Capabilities, BufferLength);
768     RtlCopyMemory(Capabilities, &HubCaps, Length);
769 
770     Irp->IoStatus.Information = Length;
771 
772     USBH_CompleteIrp(Irp, STATUS_SUCCESS);
773 
774     return STATUS_SUCCESS;
775 }
776 
777 NTSTATUS
778 NTAPI
779 USBH_IoctlGetNodeConnectionAttributes(IN PUSBHUB_FDO_EXTENSION HubExtension,
780                                       IN PIRP Irp)
781 {
782     PUSB_NODE_CONNECTION_ATTRIBUTES Attributes;
783     ULONG ConnectionIndex;
784     ULONG NumPorts;
785     NTSTATUS Status;
786     PUSBHUB_PORT_DATA PortData;
787     PIO_STACK_LOCATION IoStack;
788     ULONG BufferLength;
789 
790     DPRINT("USBH_IoctlGetNodeConnectionAttributes ... \n");
791 
792     IoStack = IoGetCurrentIrpStackLocation(Irp);
793     BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
794 
795     if (BufferLength < sizeof(USB_NODE_CONNECTION_ATTRIBUTES))
796     {
797         Status = STATUS_BUFFER_TOO_SMALL;
798         goto Exit;
799     }
800 
801     Attributes = Irp->AssociatedIrp.SystemBuffer;
802 
803     ConnectionIndex = Attributes->ConnectionIndex;
804     RtlZeroMemory(Attributes, BufferLength);
805     Attributes->ConnectionIndex = ConnectionIndex;
806 
807     Status = STATUS_INVALID_PARAMETER;
808 
809     NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
810 
811     if (NumPorts == 0 ||
812         ConnectionIndex == 0 ||
813         ConnectionIndex > NumPorts)
814     {
815         goto Exit;
816     }
817 
818     PortData = HubExtension->PortData + (ConnectionIndex - 1);
819 
820     Attributes->ConnectionStatus = PortData->ConnectionStatus;
821     Attributes->PortAttributes = PortData->PortAttributes;
822 
823     Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_ATTRIBUTES);
824     Status = STATUS_SUCCESS;
825 
826 Exit:
827 
828     USBH_CompleteIrp(Irp, Status);
829     return Status;
830 }
831 
832 NTSTATUS
833 NTAPI
834 USBH_IoctlGetNodeConnectionInformation(IN PUSBHUB_FDO_EXTENSION HubExtension,
835                                        IN PIRP Irp,
836                                        IN BOOLEAN IsExt)
837 {
838     PUSBHUB_PORT_DATA PortData;
839     ULONG BufferLength;
840     PUSB_NODE_CONNECTION_INFORMATION_EX Info;
841     ULONG ConnectionIndex;
842     ULONG NumPorts;
843     NTSTATUS Status;
844     PDEVICE_OBJECT DeviceObject;
845     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
846     PIO_STACK_LOCATION IoStack;
847 
848     DPRINT("USBH_IoctlGetNodeConnectionInformation ... \n");
849 
850     IoStack = IoGetCurrentIrpStackLocation(Irp);
851     BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
852 
853     if (BufferLength < (ULONG)FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
854                                            PipeList))
855     {
856         Status = STATUS_BUFFER_TOO_SMALL;
857         goto Exit;
858     }
859 
860     Info = Irp->AssociatedIrp.SystemBuffer;
861 
862     ConnectionIndex = Info->ConnectionIndex;
863     RtlZeroMemory(Info, BufferLength);
864     Info->ConnectionIndex = ConnectionIndex;
865 
866     Status = STATUS_INVALID_PARAMETER;
867 
868     NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
869 
870     if (NumPorts == 0 ||
871         ConnectionIndex == 0 ||
872         ConnectionIndex > NumPorts)
873     {
874         goto Exit;
875     }
876 
877     PortData = HubExtension->PortData + (ConnectionIndex - 1);
878     DeviceObject = PortData->DeviceObject;
879 
880     if (!DeviceObject)
881     {
882         Info->ConnectionStatus = PortData->ConnectionStatus;
883 
884         Irp->IoStatus.Information = FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
885                                                  PipeList);
886         Status = STATUS_SUCCESS;
887         goto Exit;
888     }
889 
890     PortExtension = DeviceObject->DeviceExtension;
891 
892     Info->ConnectionStatus = PortData->ConnectionStatus;
893 
894     Info->DeviceIsHub = (PortExtension->PortPdoFlags &
895                          USBHUB_PDO_FLAG_HUB_DEVICE) ==
896                          USBHUB_PDO_FLAG_HUB_DEVICE;
897 
898     RtlCopyMemory(&Info->DeviceDescriptor,
899                   &PortExtension->DeviceDescriptor,
900                   sizeof(USB_DEVICE_DESCRIPTOR));
901 
902     if (PortExtension->DeviceHandle)
903     {
904         Status = USBD_GetDeviceInformationEx(PortExtension,
905                                              HubExtension,
906                                              Info,
907                                              BufferLength,
908                                              PortExtension->DeviceHandle);
909     }
910     else
911     {
912         Status = STATUS_SUCCESS;
913     }
914 
915     if (NT_SUCCESS(Status))
916     {
917         if (!IsExt)
918         {
919             /* IOCTL_USB_GET_NODE_CONNECTION_INFORMATION request reports
920                only low and full speed connections. Info->Speed member
921                is Info->LowSpeed in the non-EX version of the structure */
922 
923             Info->Speed = (Info->Speed == UsbLowSpeed);
924         }
925 
926         Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
927                                     (Info->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFO);
928         goto Exit;
929     }
930 
931     if (Status != STATUS_BUFFER_TOO_SMALL)
932     {
933         goto Exit;
934     }
935 
936     Irp->IoStatus.Information = FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
937                                              PipeList);
938     Status = STATUS_SUCCESS;
939 
940 Exit:
941     USBH_CompleteIrp(Irp, Status);
942     return Status;
943 }
944 
945 NTSTATUS
946 NTAPI
947 USBH_IoctlGetNodeConnectionDriverKeyName(IN PUSBHUB_FDO_EXTENSION HubExtension,
948                                          IN PIRP Irp)
949 {
950     PUSBHUB_PORT_DATA PortData;
951     PDEVICE_OBJECT PortDevice;
952     ULONG Length;
953     ULONG ResultLength;
954     NTSTATUS Status;
955     PIO_STACK_LOCATION IoStack;
956     ULONG BufferLength;
957     PUSB_NODE_CONNECTION_DRIVERKEY_NAME KeyName;
958     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
959 
960     DPRINT("USBH_IoctlGetNodeConnectionDriverKeyName ... \n");
961 
962     IoStack = IoGetCurrentIrpStackLocation(Irp);
963     BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
964 
965     if (BufferLength < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) ||
966         HubExtension->HubDescriptor->bNumberOfPorts == 0)
967     {
968         Status = STATUS_BUFFER_TOO_SMALL;
969         goto Exit;
970     }
971 
972     KeyName = Irp->AssociatedIrp.SystemBuffer;
973     Status = STATUS_INVALID_PARAMETER;
974 
975     PortData = &HubExtension->PortData[KeyName->ConnectionIndex - 1];
976     PortDevice = PortData->DeviceObject;
977 
978     if (!PortDevice)
979     {
980         goto Exit;
981     }
982 
983     PortExtension = PortDevice->DeviceExtension;
984 
985     if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_ENUMERATED))
986     {
987         Status = STATUS_INVALID_DEVICE_STATE;
988         goto Exit;
989     }
990 
991     ResultLength = BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
992 
993     Status = IoGetDeviceProperty(PortDevice,
994                                  DevicePropertyDriverKeyName,
995                                  BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
996                                  &KeyName->DriverKeyName,
997                                  &ResultLength);
998 
999     if (Status == STATUS_BUFFER_TOO_SMALL)
1000     {
1001         Status = STATUS_SUCCESS;
1002     }
1003 
1004     Length = ResultLength + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
1005     KeyName->ActualLength = Length;
1006 
1007     if (BufferLength < Length)
1008     {
1009         KeyName->DriverKeyName[0] = 0;
1010         Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
1011     }
1012     else
1013     {
1014         Irp->IoStatus.Information = Length;
1015     }
1016 
1017 Exit:
1018     USBH_CompleteIrp(Irp, Status);
1019     return Status;
1020 }
1021 
1022 NTSTATUS
1023 NTAPI
1024 USBH_IoctlGetDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension,
1025                         IN PIRP Irp)
1026 {
1027     ULONG BufferLength;
1028     PUSBHUB_PORT_DATA PortData;
1029     PUSB_DESCRIPTOR_REQUEST UsbRequest;
1030     PDEVICE_OBJECT PortDevice;
1031     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
1032     struct _URB_CONTROL_TRANSFER * Urb;
1033     NTSTATUS Status;
1034     ULONG RequestBufferLength;
1035     PIO_STACK_LOCATION IoStack;
1036     ULONG NumPorts;
1037 
1038     IoStack = IoGetCurrentIrpStackLocation(Irp);
1039     BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
1040 
1041     DPRINT("USBH_IoctlGetDescriptor: BufferLength - %x\n", BufferLength);
1042 
1043     if (BufferLength < sizeof(USB_DESCRIPTOR_REQUEST))
1044     {
1045         Status = STATUS_BUFFER_TOO_SMALL;
1046         goto Exit;
1047     }
1048 
1049     UsbRequest = Irp->AssociatedIrp.SystemBuffer;
1050     RequestBufferLength = UsbRequest->SetupPacket.wLength;
1051 
1052     if (RequestBufferLength > BufferLength -
1053                               FIELD_OFFSET(USB_DESCRIPTOR_REQUEST, Data))
1054     {
1055         DPRINT("USBH_IoctlGetDescriptor: RequestBufferLength - %x\n",
1056                RequestBufferLength);
1057 
1058         Status = STATUS_BUFFER_TOO_SMALL;
1059         goto Exit;
1060     }
1061 
1062     Status = STATUS_INVALID_PARAMETER;
1063 
1064     NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
1065 
1066     if (NumPorts == 0 ||
1067         UsbRequest->ConnectionIndex == 0 ||
1068         UsbRequest->ConnectionIndex > NumPorts)
1069     {
1070         goto Exit;
1071     }
1072 
1073     PortData = HubExtension->PortData + (UsbRequest->ConnectionIndex - 1);
1074     PortDevice = PortData->DeviceObject;
1075 
1076     if (!PortDevice)
1077     {
1078         goto Exit;
1079     }
1080 
1081     PortExtension = PortDevice->DeviceExtension;
1082 
1083     if (UsbRequest->SetupPacket.bmRequest == USB_CONFIGURATION_DESCRIPTOR_TYPE &&
1084         RequestBufferLength == sizeof(USB_CONFIGURATION_DESCRIPTOR))
1085     {
1086         Status = STATUS_SUCCESS;
1087 
1088         RtlCopyMemory(&UsbRequest->Data[0],
1089                       &PortExtension->ConfigDescriptor,
1090                       sizeof(USB_CONFIGURATION_DESCRIPTOR));
1091 
1092         Irp->IoStatus.Information = sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR) +
1093                                     sizeof(USB_CONFIGURATION_DESCRIPTOR);
1094         goto Exit;
1095     }
1096 
1097     Urb = ExAllocatePoolWithTag(NonPagedPool,
1098                                 sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
1099                                 USB_HUB_TAG);
1100 
1101     if (!Urb)
1102     {
1103         Status = STATUS_INSUFFICIENT_RESOURCES;
1104         goto Exit;
1105     }
1106 
1107     RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
1108 
1109     Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
1110     Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
1111 
1112     Urb->TransferBuffer = &UsbRequest->Data[0];
1113     Urb->TransferBufferLength = RequestBufferLength;
1114     Urb->TransferBufferMDL = NULL;
1115     Urb->UrbLink = NULL;
1116 
1117     RtlCopyMemory(Urb->SetupPacket,
1118                   &UsbRequest->SetupPacket,
1119                   sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1120 
1121     Status = USBH_SyncSubmitUrb(PortExtension->Common.SelfDevice,
1122                                 (PURB)Urb);
1123 
1124     Irp->IoStatus.Information = (sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR)) +
1125                                 Urb->TransferBufferLength;
1126 
1127     ExFreePoolWithTag(Urb, USB_HUB_TAG);
1128 
1129 Exit:
1130     USBH_CompleteIrp(Irp, Status);
1131     return Status;
1132 }
1133 
1134 NTSTATUS
1135 NTAPI
1136 USBH_DeviceControl(IN PUSBHUB_FDO_EXTENSION HubExtension,
1137                    IN PIRP Irp)
1138 {
1139     NTSTATUS Status = STATUS_DEVICE_BUSY;
1140     PIO_STACK_LOCATION IoStack;
1141     ULONG ControlCode;
1142     BOOLEAN IsCheckHubIdle = FALSE;
1143 
1144     DPRINT("USBH_DeviceControl: HubExtension - %p, Irp - %p\n",
1145            HubExtension,
1146            Irp);
1147 
1148     IoStack = IoGetCurrentIrpStackLocation(Irp);
1149     ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
1150     DPRINT("USBH_DeviceControl: ControlCode - %lX\n", ControlCode);
1151 
1152     if ((HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0) &&
1153         (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED))
1154     {
1155         IsCheckHubIdle = TRUE;
1156         USBH_HubSetD0(HubExtension);
1157     }
1158 
1159     switch (ControlCode)
1160     {
1161         case IOCTL_USB_GET_HUB_CAPABILITIES:
1162             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_HUB_CAPABILITIES\n");
1163             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1164             {
1165                 Status = USBH_IoctlGetHubCapabilities(HubExtension, Irp);
1166                 break;
1167             }
1168 
1169             USBH_CompleteIrp(Irp, Status);
1170             break;
1171 
1172         case IOCTL_USB_HUB_CYCLE_PORT:
1173             DPRINT1("USBH_DeviceControl: IOCTL_USB_HUB_CYCLE_PORT UNIMPLEMENTED. FIXME\n");
1174             DbgBreakPoint();
1175             break;
1176 
1177         case IOCTL_USB_GET_NODE_INFORMATION:
1178             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_INFORMATION\n");
1179             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1180             {
1181                 Status = USBH_IoctlGetNodeInformation(HubExtension, Irp);
1182                 break;
1183             }
1184 
1185             USBH_CompleteIrp(Irp, Status);
1186             break;
1187 
1188         case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
1189             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
1190             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1191             {
1192                 Status = USBH_IoctlGetNodeConnectionInformation(HubExtension,
1193                                                                 Irp,
1194                                                                 FALSE);
1195                 break;
1196             }
1197 
1198             USBH_CompleteIrp(Irp, Status);
1199             break;
1200 
1201         case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX:
1202             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX\n");
1203             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1204             {
1205                 Status = USBH_IoctlGetNodeConnectionInformation(HubExtension,
1206                                                                 Irp,
1207                                                                 TRUE);
1208                 break;
1209             }
1210 
1211             USBH_CompleteIrp(Irp, Status);
1212             break;
1213 
1214         case IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES:
1215             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES\n");
1216             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1217             {
1218                 Status = USBH_IoctlGetNodeConnectionAttributes(HubExtension, Irp);
1219                 break;
1220             }
1221 
1222             USBH_CompleteIrp(Irp, Status);
1223             break;
1224 
1225         case IOCTL_USB_GET_NODE_CONNECTION_NAME:
1226             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
1227             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1228             {
1229                 Status = USBH_IoctlGetNodeName(HubExtension, Irp);
1230                 break;
1231             }
1232 
1233             USBH_CompleteIrp(Irp, Status);
1234             break;
1235 
1236         case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
1237             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
1238             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1239             {
1240                 Status = USBH_IoctlGetNodeConnectionDriverKeyName(HubExtension, Irp);
1241                 break;
1242             }
1243 
1244             USBH_CompleteIrp(Irp, Status);
1245             break;
1246 
1247         case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
1248             DPRINT("USBH_DeviceControl: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
1249             if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
1250             {
1251                 Status = USBH_IoctlGetDescriptor(HubExtension, Irp);
1252                 break;
1253             }
1254 
1255             USBH_CompleteIrp(Irp, Status);
1256             break;
1257 
1258         case IOCTL_KS_PROPERTY:
1259             DPRINT("USBH_DeviceControl: IOCTL_KS_PROPERTY\n");
1260             Status = STATUS_INVALID_DEVICE_REQUEST;
1261             USBH_CompleteIrp(Irp, Status);
1262             break;
1263 
1264         default:
1265             DPRINT1("USBH_DeviceControl: Unhandled IOCTL_ - %lX\n", ControlCode);
1266             Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp);
1267             break;
1268     }
1269 
1270     if (IsCheckHubIdle)
1271     {
1272         USBH_CheckHubIdle(HubExtension);
1273     }
1274 
1275     return Status;
1276 }
1277 
1278 NTSTATUS
1279 NTAPI
1280 USBH_PdoInternalControl(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
1281                         IN PIRP Irp)
1282 {
1283     PUSBHUB_FDO_EXTENSION HubExtension;
1284     NTSTATUS Status = STATUS_NOT_SUPPORTED;
1285     ULONG ControlCode;
1286     PIO_STACK_LOCATION IoStack;
1287     PULONG HubCount;
1288 
1289     DPRINT_IOCTL("USBH_PdoInternalControl: PortExtension - %p, Irp - %p\n",
1290                  PortExtension,
1291                  Irp);
1292 
1293     HubExtension = PortExtension->HubExtension;
1294 
1295     if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED)
1296     {
1297         Status = STATUS_DEVICE_NOT_CONNECTED;
1298         goto Exit;
1299     }
1300 
1301     if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD0)
1302     {
1303         Status = STATUS_DEVICE_POWERED_OFF;
1304         goto Exit;
1305     }
1306 
1307     IoStack = IoGetCurrentIrpStackLocation(Irp);
1308     ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
1309 
1310     if (ControlCode == IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO)
1311     {
1312         HubExtension = PortExtension->RootHubExtension;
1313         DPRINT("USBH_PdoInternalControl: HubExtension - %p\n", HubExtension);
1314     }
1315 
1316     if (!HubExtension)
1317     {
1318         Status = STATUS_DEVICE_BUSY;
1319         goto Exit;
1320     }
1321 
1322     switch (ControlCode)
1323     {
1324         case IOCTL_INTERNAL_USB_SUBMIT_URB:
1325             return USBH_PdoIoctlSubmitUrb(PortExtension, Irp);
1326 
1327         case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
1328             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n");
1329             return USBH_PortIdleNotificationRequest(PortExtension, Irp);
1330 
1331         case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
1332             DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
1333             return USBH_PdoIoctlGetPortStatus(PortExtension, Irp);
1334 
1335         case IOCTL_INTERNAL_USB_RESET_PORT:
1336             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_RESET_PORT\n");
1337             return USBH_PdoIoctlResetPort(PortExtension, Irp);
1338 
1339         case IOCTL_INTERNAL_USB_ENABLE_PORT:
1340             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_ENABLE_PORT\n");
1341             DbgBreakPoint();
1342             break;
1343 
1344         case IOCTL_INTERNAL_USB_CYCLE_PORT:
1345             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_CYCLE_PORT\n");
1346             DbgBreakPoint();
1347             break;
1348 
1349         case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
1350             DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
1351             *(PVOID *)IoStack->Parameters.Others.Argument1 = PortExtension->DeviceHandle;
1352             Status = STATUS_SUCCESS;
1353             break;
1354 
1355         case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
1356             DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_COUNT. PortPdoFlags - %lX\n",
1357                    PortExtension->PortPdoFlags);
1358 
1359             if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE))
1360             {
1361                 Status = STATUS_INVALID_PARAMETER;
1362                 break;
1363             }
1364 
1365             HubCount = IoStack->Parameters.Others.Argument1;
1366 
1367             ++*HubCount;
1368 
1369             Status = USBH_SyncGetHubCount(HubExtension->LowerDevice,
1370                                           HubCount);
1371 
1372             DPRINT("USBH_PdoInternalControl: *HubCount - %x\n", *HubCount);
1373             break;
1374 
1375         case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
1376             DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO. PortPdoFlags - %lX\n",
1377                    PortExtension->PortPdoFlags);
1378 
1379             if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE))
1380             {
1381                 DbgBreakPoint();
1382                 Status = STATUS_SUCCESS;
1383 
1384                 *(PVOID *)IoStack->Parameters.Others.Argument1 = NULL;
1385 
1386                 USBH_CompleteIrp(Irp, Status);
1387                 break;
1388             }
1389 
1390             ASSERT(HubExtension->RootHubPdo);
1391             return USBH_PassIrp(HubExtension->RootHubPdo, Irp);
1392 
1393         case IOCTL_INTERNAL_USB_GET_HUB_NAME:
1394             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_NAME\n");
1395             DbgBreakPoint();
1396             break;
1397 
1398         case IOCTL_GET_HCD_DRIVERKEY_NAME:
1399             DPRINT1("USBH_PdoInternalControl: IOCTL_GET_HCD_DRIVERKEY_NAME\n");
1400             DbgBreakPoint();
1401             break;
1402 
1403         case IOCTL_INTERNAL_USB_GET_BUS_INFO:
1404             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_BUS_INFO\n");
1405             DbgBreakPoint();
1406             break;
1407 
1408         case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
1409             DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
1410             DbgBreakPoint();
1411             break;
1412 
1413         default:
1414             DPRINT1("USBH_PdoInternalControl: unhandled IOCTL_ - %lX\n", ControlCode);
1415             break;
1416     }
1417 
1418 Exit:
1419     USBH_CompleteIrp(Irp, Status);
1420     return Status;
1421 }
1422