--- /dev/null
+/*
+ * PROJECT: ReactOS USB Hub Driver
+ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: USBHub I/O control functions
+ * COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
+ */
+
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_IOCTL
+#include "dbg_uhub.h"
+
+NTSTATUS
+NTAPI
+USBH_SelectConfigOrInterfaceComplete(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PVOID TimeoutContext; // PUSBHUB_BANDWIDTH_TIMEOUT_CONTEXT
+ PUSBHUB_PORT_DATA PortData = NULL;
+ NTSTATUS Status;
+ KIRQL OldIrql;
+
+ DPRINT("USBH_SelectConfigOrInterfaceComplete ... \n");
+
+ if (Irp->PendingReturned)
+ {
+ IoMarkIrpPending(Irp);
+ }
+
+ PortExtension = Context;
+ HubExtension = PortExtension->HubExtension;
+
+ ASSERT(PortExtension->PortNumber > 0);
+
+ if (HubExtension)
+ {
+ PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
+ }
+
+ Status = Irp->IoStatus.Status;
+
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ KeAcquireSpinLock(&PortExtension->PortTimeoutSpinLock, &OldIrql);
+
+ TimeoutContext = PortExtension->BndwTimeoutContext;
+
+ if (TimeoutContext)
+ {
+ DPRINT1("USBH_SelectConfigOrInterfaceComplete: TimeoutContext != NULL. FIXME\n");
+ DbgBreakPoint();
+ }
+
+ KeReleaseSpinLock(&PortExtension->PortTimeoutSpinLock, OldIrql);
+
+ PortExtension->PortPdoFlags &= ~(USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
+ USBHUB_PDO_FLAG_ALLOC_BNDW_FAILED);
+
+ if (PortData && PortData->ConnectionStatus != DeviceHubNestedTooDeeply)
+ {
+ PortData->ConnectionStatus = DeviceConnected;
+ }
+ }
+ else
+ {
+ DPRINT1("USBH_SelectConfigOrInterfaceComplete: Status != STATUS_SUCCESS. FIXME\n");
+ DbgBreakPoint();
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoUrbFilter(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PDEVICE_OBJECT DeviceObject;
+ PURB Urb;
+ USHORT Function;
+ ULONG MaxPower;
+ USBD_STATUS UrbStatus;
+ BOOLEAN IsValidConfig;
+
+ HubExtension = PortExtension->HubExtension;
+ DeviceObject = PortExtension->Common.SelfDevice;
+
+ Urb = URB_FROM_IRP(Irp);
+
+ DPRINT_IOCTL("USBH_PdoUrbFilter: Device - %p, Irp - %p, Urb - %p\n",
+ DeviceObject,
+ Irp,
+ Urb);
+
+ if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
+ USBHUB_PDO_FLAG_PORT_RESSETING))
+ {
+ Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
+ USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Function = Urb->UrbHeader.Function;
+
+ switch (Function)
+ {
+ case URB_FUNCTION_SELECT_CONFIGURATION:
+ {
+ ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor;
+
+ if (ConfigDescriptor)
+ {
+ IsValidConfig = TRUE;
+
+ if (ConfigDescriptor->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE)
+ {
+ DPRINT1("USBH_PdoUrbFilter: Not valid Cfg. bDescriptorType\n");
+ IsValidConfig = FALSE;
+ UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR;
+ }
+
+ if (ConfigDescriptor->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
+ {
+ DPRINT1("USBH_PdoUrbFilter: Size Cfg. descriptor is too small\n");
+ IsValidConfig = FALSE;
+ UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR;
+ }
+
+ if (!IsValidConfig)
+ {
+ Urb->UrbHeader.Status = UrbStatus;
+ USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ MaxPower = 2 * ConfigDescriptor->MaxPower;
+ PortExtension->MaxPower = MaxPower;
+
+ if (HubExtension->MaxPowerPerPort < MaxPower)
+ {
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INSUFFICIENT_PWR;
+
+ DPRINT1("USBH_PdoUrbFilter: USBH_InvalidatePortDeviceState() UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+
+ USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ /* fall through */
+
+ case URB_FUNCTION_SELECT_INTERFACE:
+ {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_SelectConfigOrInterfaceComplete,
+ PortExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ return IoCallDriver(HubExtension->RootHubPdo2, Irp);
+ }
+
+ case URB_FUNCTION_CONTROL_TRANSFER:
+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+ case URB_FUNCTION_ISOCH_TRANSFER:
+ {
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING)
+ {
+ Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
+ USBH_CompleteIrp(Irp, STATUS_DELETE_PENDING);
+ return STATUS_DELETE_PENDING;
+ }
+
+ break;
+ }
+
+ case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR:
+ DPRINT1("USBH_PdoUrbFilter: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR UNIMPLEMENTED. FIXME\n");
+ USBH_CompleteIrp(Irp, STATUS_NOT_IMPLEMENTED);
+ return STATUS_NOT_IMPLEMENTED;
+
+ default:
+ break;
+ }
+
+ return USBH_PassIrp(HubExtension->RootHubPdo2, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoIoctlSubmitUrb(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PURB Urb;
+ NTSTATUS Status;
+
+ DPRINT_IOCTL("USBH_PdoIoctlSubmitUrb ... \n");
+
+ HubExtension = PortExtension->HubExtension;
+
+ Urb = URB_FROM_IRP(Irp);
+
+ if (PortExtension->DeviceHandle == NULL)
+ {
+ Urb->UrbHeader.UsbdDeviceHandle = NULL;
+ Status = USBH_PassIrp(HubExtension->RootHubPdo2, Irp);
+ }
+ else
+ {
+ Urb->UrbHeader.UsbdDeviceHandle = PortExtension->DeviceHandle;
+ Status = USBH_PdoUrbFilter(PortExtension, Irp);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoIoctlGetPortStatus(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PUSBHUB_PORT_DATA PortData;
+ PIO_STACK_LOCATION IoStack;
+ PULONG PortStatus;
+ NTSTATUS Status;
+
+ DPRINT("USBH_PdoIoctlGetPortStatus ... \n");
+
+ HubExtension = PortExtension->HubExtension;
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->HubSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ASSERT(PortExtension->PortNumber > 0);
+ PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ PortExtension->PortNumber,
+ &PortData->PortStatus,
+ sizeof(USB_PORT_STATUS_AND_CHANGE));
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ PortStatus = IoStack->Parameters.Others.Argument1;
+
+ *PortStatus = 0;
+
+ if (PortExtension->Common.SelfDevice == PortData->DeviceObject)
+ {
+ if (PortData->PortStatus.PortStatus.Usb20PortStatus.PortEnabledDisabled)
+ {
+ *PortStatus |= USBD_PORT_ENABLED;
+ }
+
+ if (PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
+ {
+ *PortStatus |= USBD_PORT_CONNECTED;
+ }
+ }
+
+ KeReleaseSemaphore(&HubExtension->HubSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_ResetPortWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ PUSBHUB_RESET_PORT_CONTEXT WorkItemReset;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PUSB_DEVICE_HANDLE DeviceHandle;
+ NTSTATUS Status;
+ USHORT Port;
+
+ DPRINT("USBH_ResetPortWorker ... \n");
+
+ WorkItemReset = Context;
+
+ PortExtension = WorkItemReset->PortExtension;
+
+ if (!HubExtension)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ goto Exit;
+ }
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->HubSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ Port = PortExtension->PortNumber;
+ DeviceHandle = PortExtension->DeviceHandle;
+
+ ASSERT(Port > 0);
+
+ if (PortExtension->Common.SelfDevice == HubExtension->PortData[Port-1].DeviceObject &&
+ DeviceHandle != NULL)
+ {
+ USBD_RemoveDeviceEx(HubExtension,
+ DeviceHandle,
+ USBD_MARK_DEVICE_BUSY);
+
+ Status = USBH_ResetDevice(HubExtension,
+ Port,
+ TRUE,
+ FALSE);
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ KeReleaseSemaphore(&HubExtension->HubSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+Exit:
+
+ PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESSETING;
+
+ USBH_CompleteIrp(WorkItemReset->Irp, Status);
+
+ WorkItemReset->PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoIoctlResetPort(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PUSBHUB_RESET_PORT_CONTEXT HubWorkItemBuffer;
+ PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+ NTSTATUS Status;
+
+ HubExtension = PortExtension->HubExtension;
+
+ DPRINT("USBH_PdoIoctlResetPort ... \n");
+
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_RESSETING)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+ }
+
+ Status = USBH_AllocateWorkItem(HubExtension,
+ &HubIoWorkItem,
+ USBH_ResetPortWorker,
+ sizeof(USBHUB_RESET_PORT_CONTEXT),
+ (PVOID *)&HubWorkItemBuffer,
+ DelayedWorkQueue);
+
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+ }
+
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_PORT_RESSETING;
+ IoMarkIrpPending(Irp);
+
+ HubWorkItemBuffer->PortExtension = PortExtension;
+ HubWorkItemBuffer->Irp = Irp;
+
+ Status = STATUS_PENDING;
+
+ USBH_QueueWorkItem(PortExtension->HubExtension, HubIoWorkItem);
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_PortIdleNotificationCancelRoutine(IN PDEVICE_OBJECT Device,
+ IN PIRP Irp)
+{
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PIRP PendingIdleIrp = NULL;
+ PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+ PUSBHUB_IDLE_PORT_CANCEL_CONTEXT HubWorkItemBuffer;
+ NTSTATUS Status;
+
+ DPRINT("USBH_PortIdleNotificationCancelRoutine ... \n");
+
+ PortExtension = Device->DeviceExtension;
+ PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
+
+ HubExtension = PortExtension->HubExtension;
+ ASSERT(HubExtension);
+
+ PortExtension->IdleNotificationIrp = NULL;
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+ {
+ PendingIdleIrp = HubExtension->PendingIdleIrp;
+ HubExtension->PendingIdleIrp = NULL;
+ }
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ if (PendingIdleIrp)
+ {
+ USBH_HubCancelIdleIrp(HubExtension, PendingIdleIrp);
+ }
+
+ if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
+ {
+ goto ErrorExit;
+ }
+
+ Status = USBH_AllocateWorkItem(HubExtension,
+ &HubIoWorkItem,
+ USBH_IdleCancelPowerHubWorker,
+ sizeof(USBHUB_IDLE_PORT_CANCEL_CONTEXT),
+ (PVOID *)&HubWorkItemBuffer,
+ DelayedWorkQueue);
+
+ if (NT_SUCCESS(Status))
+ {
+ HubWorkItemBuffer->Irp = Irp;
+ USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+ return;
+ }
+
+ErrorExit:
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+NTSTATUS
+NTAPI
+USBH_PortIdleNotificationRequest(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PIO_STACK_LOCATION IoStack;
+ PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo;
+ NTSTATUS Status;
+ KIRQL Irql;
+
+ DPRINT("USBH_PortIdleNotificationRequest ... \n");
+
+ HubExtension = PortExtension->HubExtension;
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ if (PortExtension->IdleNotificationIrp)
+ {
+ IoReleaseCancelSpinLock(Irql);
+ Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_DEVICE_BUSY;
+ }
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ IdleCallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ if (!IdleCallbackInfo || !IdleCallbackInfo->IdleCallback)
+ {
+ IoReleaseCancelSpinLock(Irql);
+
+ Status = STATUS_NO_CALLBACK_ACTIVE;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+ }
+
+ IoSetCancelRoutine(Irp, USBH_PortIdleNotificationCancelRoutine);
+
+ if (Irp->Cancel)
+ {
+ if (IoSetCancelRoutine(Irp, NULL))
+ {
+ IoReleaseCancelSpinLock(Irql);
+ Status = STATUS_CANCELLED;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ IoMarkIrpPending(Irp);
+ IoReleaseCancelSpinLock(Irql);
+ Status = STATUS_PENDING;
+ }
+ }
+ else
+ {
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
+
+ PortExtension->IdleNotificationIrp = Irp;
+ IoMarkIrpPending(Irp);
+
+ IoReleaseCancelSpinLock(Irql);
+ Status = STATUS_PENDING;
+
+ DPRINT("USBH_PortIdleNotificationRequest: IdleNotificationIrp - %p\n",
+ PortExtension->IdleNotificationIrp);
+
+ USBH_CheckIdleDeferred(HubExtension);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeName(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ PUSB_NODE_CONNECTION_NAME ConnectionName;
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ size_t LengthSkip;
+ PWCHAR Buffer;
+ ULONG BufferLength;
+ PWCHAR BufferEnd;
+ ULONG_PTR LengthReturned;
+ size_t LengthName;
+ ULONG Length;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ ULONG_PTR Information;
+
+ DPRINT("USBH_IoctlGetNodeName ... \n");
+
+ Status = STATUS_SUCCESS;
+
+ ConnectionName = Irp->AssociatedIrp.SystemBuffer;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (Length < sizeof(USB_NODE_CONNECTION_NAME))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ Information = Irp->IoStatus.Information;
+ goto Exit;
+ }
+
+ if (ConnectionName->ConnectionIndex == 0 ||
+ ConnectionName->ConnectionIndex > HubExtension->HubDescriptor->bNumberOfPorts)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ Information = Irp->IoStatus.Information;
+ goto Exit;
+ }
+
+ PortDevice = HubExtension->PortData[ConnectionName->ConnectionIndex - 1].DeviceObject;
+
+ if (!PortDevice)
+ {
+ ConnectionName->NodeName[0] = 0;
+ ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME);
+
+ Information = sizeof(USB_NODE_CONNECTION_NAME);
+ goto Exit;
+ }
+
+ PortExtension = PortDevice->DeviceExtension;
+
+ if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE) ||
+ !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DEVICE_STARTED) ||
+ !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE))
+ {
+ ConnectionName->NodeName[0] = 0;
+ ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME);
+
+ Information = sizeof(USB_NODE_CONNECTION_NAME);
+ goto Exit;
+ }
+
+ Buffer = PortExtension->SymbolicLinkName.Buffer;
+ BufferLength = PortExtension->SymbolicLinkName.Length;
+
+ ASSERT(Buffer[BufferLength / sizeof(WCHAR)] == UNICODE_NULL);
+
+ LengthSkip = 0;
+
+ if (*Buffer == L'\\')
+ {
+ BufferEnd = wcschr(Buffer + 1, L'\\');
+
+ if (BufferEnd != NULL)
+ {
+ LengthSkip = (BufferEnd + 1 - Buffer) * sizeof(WCHAR);
+ }
+ else
+ {
+ LengthSkip = PortExtension->SymbolicLinkName.Length;
+ }
+ }
+
+ LengthName = BufferLength - LengthSkip;
+
+ ConnectionName->ActualLength = 0;
+
+ RtlZeroMemory(ConnectionName->NodeName,
+ Length - FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName));
+
+ LengthReturned = sizeof(USB_NODE_CONNECTION_NAME) + LengthName;
+
+ if (Length < LengthReturned)
+ {
+ ConnectionName->NodeName[0] = 0;
+ ConnectionName->ActualLength = LengthReturned;
+
+ Information = sizeof(USB_NODE_CONNECTION_NAME);
+ goto Exit;
+ }
+
+ RtlCopyMemory(&ConnectionName->NodeName[0],
+ &Buffer[LengthSkip / sizeof(WCHAR)],
+ LengthName);
+
+ ConnectionName->ActualLength = LengthReturned;
+
+ Status = STATUS_SUCCESS;
+ Information = LengthReturned;
+
+Exit:
+ Irp->IoStatus.Information = Information;
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeInformation(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ PUSB_NODE_INFORMATION NodeInfo;
+ PIO_STACK_LOCATION IoStack;
+ ULONG BufferLength;
+ NTSTATUS Status;
+ BOOLEAN HubIsBusPowered;
+
+ DPRINT("USBH_IoctlGetNodeInformation ... \n");
+
+ Status = STATUS_SUCCESS;
+
+ NodeInfo = Irp->AssociatedIrp.SystemBuffer;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, BufferLength);
+
+ if (BufferLength < sizeof(USB_NODE_INFORMATION))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+ }
+
+ NodeInfo->NodeType = UsbHub;
+
+ RtlCopyMemory(&NodeInfo->u.HubInformation.HubDescriptor,
+ HubExtension->HubDescriptor,
+ sizeof(USB_HUB_DESCRIPTOR));
+
+ HubIsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice,
+ HubExtension->HubConfigDescriptor);
+
+ NodeInfo->u.HubInformation.HubIsBusPowered = HubIsBusPowered;
+
+ Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
+
+ USBH_CompleteIrp(Irp, Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetHubCapabilities(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ PUSB_HUB_CAPABILITIES Capabilities;
+ PIO_STACK_LOCATION IoStack;
+ ULONG BufferLength;
+ ULONG Length;
+ USB_HUB_CAPABILITIES HubCaps;
+
+ DPRINT("USBH_IoctlGetHubCapabilities ... \n");
+
+ Capabilities = Irp->AssociatedIrp.SystemBuffer;
+
+ HubCaps.HubIs2xCapable = (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB) ==
+ USBHUB_FDO_FLAG_USB20_HUB;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (BufferLength == 0)
+ {
+ Irp->IoStatus.Information = BufferLength;
+ USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (BufferLength <= sizeof(HubCaps))
+ {
+ Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+ }
+ else
+ {
+ Length = sizeof(HubCaps);
+ }
+
+ RtlZeroMemory(Capabilities, BufferLength);
+ RtlCopyMemory(Capabilities, &HubCaps, Length);
+
+ Irp->IoStatus.Information = Length;
+
+ USBH_CompleteIrp(Irp, STATUS_SUCCESS);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeConnectionAttributes(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ PUSB_NODE_CONNECTION_ATTRIBUTES Attributes;
+ ULONG ConnectionIndex;
+ ULONG NumPorts;
+ NTSTATUS Status;
+ PUSBHUB_PORT_DATA PortData;
+ PIO_STACK_LOCATION IoStack;
+ ULONG BufferLength;
+
+ DPRINT("USBH_IoctlGetNodeConnectionAttributes ... \n");
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (BufferLength < sizeof(USB_NODE_CONNECTION_ATTRIBUTES))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+
+ Attributes = Irp->AssociatedIrp.SystemBuffer;
+
+ ConnectionIndex = Attributes->ConnectionIndex;
+ RtlZeroMemory(Attributes, BufferLength);
+ Attributes->ConnectionIndex = ConnectionIndex;
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ if (NumPorts == 0 ||
+ ConnectionIndex == 0 ||
+ ConnectionIndex > NumPorts)
+ {
+ goto Exit;
+ }
+
+ PortData = HubExtension->PortData + (ConnectionIndex - 1);
+
+ Attributes->ConnectionStatus = PortData->ConnectionStatus;
+ Attributes->PortAttributes = PortData->PortAttributes;
+
+ Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_ATTRIBUTES);
+ Status = STATUS_SUCCESS;
+
+Exit:
+
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeConnectionInformation(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN BOOLEAN IsExt)
+{
+ PUSBHUB_PORT_DATA PortData;
+ ULONG BufferLength;
+ PUSB_NODE_CONNECTION_INFORMATION_EX Info;
+ ULONG ConnectionIndex;
+ ULONG NumPorts;
+ NTSTATUS Status;
+ PDEVICE_OBJECT DeviceObject;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PIO_STACK_LOCATION IoStack;
+
+ DPRINT("USBH_IoctlGetNodeConnectionInformation ... \n");
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (BufferLength < (ULONG)FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
+ PipeList))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+
+ Info = Irp->AssociatedIrp.SystemBuffer;
+
+ ConnectionIndex = Info->ConnectionIndex;
+ RtlZeroMemory(Info, BufferLength);
+ Info->ConnectionIndex = ConnectionIndex;
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ if (NumPorts == 0 ||
+ ConnectionIndex == 0 ||
+ ConnectionIndex > NumPorts)
+ {
+ goto Exit;
+ }
+
+ PortData = HubExtension->PortData + (ConnectionIndex - 1);
+ DeviceObject = PortData->DeviceObject;
+
+ if (!DeviceObject)
+ {
+ Info->ConnectionStatus = PortData->ConnectionStatus;
+
+ Irp->IoStatus.Information = FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
+ PipeList);
+ Status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ PortExtension = DeviceObject->DeviceExtension;
+
+ Info->ConnectionStatus = PortData->ConnectionStatus;
+
+ Info->DeviceIsHub = (PortExtension->PortPdoFlags &
+ USBHUB_PDO_FLAG_HUB_DEVICE) ==
+ USBHUB_PDO_FLAG_HUB_DEVICE;
+
+ RtlCopyMemory(&Info->DeviceDescriptor,
+ &PortExtension->DeviceDescriptor,
+ sizeof(USB_DEVICE_DESCRIPTOR));
+
+ if (PortExtension->DeviceHandle)
+ {
+ Status = USBD_GetDeviceInformationEx(PortExtension,
+ HubExtension,
+ Info,
+ BufferLength,
+ PortExtension->DeviceHandle);
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ if (!IsExt)
+ {
+ /* IOCTL_USB_GET_NODE_CONNECTION_INFORMATION request reports
+ only low and full speed connections. Info->Speed member
+ is Info->LowSpeed in the non-EX version of the structure */
+
+ Info->Speed = (Info->Speed == UsbLowSpeed);
+ }
+
+ Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
+ (Info->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFO);
+ goto Exit;
+ }
+
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ goto Exit;
+ }
+
+ Irp->IoStatus.Information = FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
+ PipeList);
+ Status = STATUS_SUCCESS;
+
+Exit:
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeConnectionDriverKeyName(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ PUSBHUB_PORT_DATA PortData;
+ PDEVICE_OBJECT PortDevice;
+ ULONG Length;
+ ULONG ResultLength;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ ULONG BufferLength;
+ PUSB_NODE_CONNECTION_DRIVERKEY_NAME KeyName;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+
+ DPRINT("USBH_IoctlGetNodeConnectionDriverKeyName ... \n");
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (BufferLength < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) ||
+ HubExtension->HubDescriptor->bNumberOfPorts == 0)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+
+ KeyName = Irp->AssociatedIrp.SystemBuffer;
+ Status = STATUS_INVALID_PARAMETER;
+
+ PortData = &HubExtension->PortData[KeyName->ConnectionIndex - 1];
+ PortDevice = PortData->DeviceObject;
+
+ if (!PortDevice)
+ {
+ goto Exit;
+ }
+
+ PortExtension = PortDevice->DeviceExtension;
+
+ if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_ENUMERATED))
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ ResultLength = BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+
+ Status = IoGetDeviceProperty(PortDevice,
+ DevicePropertyDriverKeyName,
+ BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
+ &KeyName->DriverKeyName,
+ &ResultLength);
+
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ Length = ResultLength + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+ KeyName->ActualLength = Length;
+
+ if (BufferLength < Length)
+ {
+ KeyName->DriverKeyName[0] = 0;
+ Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+ }
+ else
+ {
+ Irp->IoStatus.Information = Length;
+ }
+
+Exit:
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ ULONG BufferLength;
+ PUSBHUB_PORT_DATA PortData;
+ PUSB_DESCRIPTOR_REQUEST UsbRequest;
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ struct _URB_CONTROL_TRANSFER * Urb;
+ NTSTATUS Status;
+ ULONG RequestBufferLength;
+ PIO_STACK_LOCATION IoStack;
+ ULONG NumPorts;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ DPRINT("USBH_IoctlGetDescriptor: BufferLength - %x\n", BufferLength);
+
+ if (BufferLength < sizeof(USB_DESCRIPTOR_REQUEST))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+
+ UsbRequest = Irp->AssociatedIrp.SystemBuffer;
+ RequestBufferLength = UsbRequest->SetupPacket.wLength;
+
+ if (RequestBufferLength > BufferLength -
+ FIELD_OFFSET(USB_DESCRIPTOR_REQUEST, Data))
+ {
+ DPRINT("USBH_IoctlGetDescriptor: RequestBufferLength - %x\n",
+ RequestBufferLength);
+
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ if (NumPorts == 0 ||
+ UsbRequest->ConnectionIndex == 0 ||
+ UsbRequest->ConnectionIndex > NumPorts)
+ {
+ goto Exit;
+ }
+
+ PortData = HubExtension->PortData + (UsbRequest->ConnectionIndex - 1);
+ PortDevice = PortData->DeviceObject;
+
+ if (!PortDevice)
+ {
+ goto Exit;
+ }
+
+ PortExtension = PortDevice->DeviceExtension;
+
+ if (UsbRequest->SetupPacket.bmRequest == USB_CONFIGURATION_DESCRIPTOR_TYPE &&
+ RequestBufferLength == sizeof(USB_CONFIGURATION_DESCRIPTOR))
+ {
+ Status = STATUS_SUCCESS;
+
+ RtlCopyMemory(&UsbRequest->Data[0],
+ &PortExtension->ConfigDescriptor,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+ Irp->IoStatus.Information = sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR) +
+ sizeof(USB_CONFIGURATION_DESCRIPTOR);
+ goto Exit;
+ }
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_HUB_TAG);
+
+ if (!Urb)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+ Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+ Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+
+ Urb->TransferBuffer = &UsbRequest->Data[0];
+ Urb->TransferBufferLength = RequestBufferLength;
+ Urb->TransferBufferMDL = NULL;
+ Urb->UrbLink = NULL;
+
+ RtlCopyMemory(Urb->SetupPacket,
+ &UsbRequest->SetupPacket,
+ sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
+
+ Status = USBH_SyncSubmitUrb(PortExtension->Common.SelfDevice,
+ (PURB)Urb);
+
+ Irp->IoStatus.Information = (sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR)) +
+ Urb->TransferBufferLength;
+
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+Exit:
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_DeviceControl(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ NTSTATUS Status = STATUS_DEVICE_BUSY;
+ PIO_STACK_LOCATION IoStack;
+ ULONG ControlCode;
+ BOOLEAN IsCheckHubIdle = FALSE;
+
+ DPRINT("USBH_DeviceControl: HubExtension - %p, Irp - %p\n",
+ HubExtension,
+ Irp);
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
+ DPRINT("USBH_DeviceControl: ControlCode - %lX\n", ControlCode);
+
+ if ((HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0) &&
+ (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED))
+ {
+ IsCheckHubIdle = TRUE;
+ USBH_HubSetD0(HubExtension);
+ }
+
+ switch (ControlCode)
+ {
+ case IOCTL_USB_GET_HUB_CAPABILITIES:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_HUB_CAPABILITIES\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetHubCapabilities(HubExtension, Irp);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_HUB_CYCLE_PORT:
+ DPRINT1("USBH_DeviceControl: IOCTL_USB_HUB_CYCLE_PORT UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ break;
+
+ case IOCTL_USB_GET_NODE_INFORMATION:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_INFORMATION\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetNodeInformation(HubExtension, Irp);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetNodeConnectionInformation(HubExtension,
+ Irp,
+ FALSE);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetNodeConnectionInformation(HubExtension,
+ Irp,
+ TRUE);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetNodeConnectionAttributes(HubExtension, Irp);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_GET_NODE_CONNECTION_NAME:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetNodeName(HubExtension, Irp);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetNodeConnectionDriverKeyName(HubExtension, Irp);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
+ DPRINT("USBH_DeviceControl: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ Status = USBH_IoctlGetDescriptor(HubExtension, Irp);
+ break;
+ }
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IOCTL_KS_PROPERTY:
+ DPRINT("USBH_DeviceControl: IOCTL_KS_PROPERTY\n");
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ default:
+ DPRINT1("USBH_DeviceControl: Unhandled IOCTL_ - %lX\n", ControlCode);
+ Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp);
+ break;
+ }
+
+ if (IsCheckHubIdle)
+ {
+ USBH_CheckHubIdle(HubExtension);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoInternalControl(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ NTSTATUS Status = STATUS_NOT_SUPPORTED;
+ ULONG ControlCode;
+ PIO_STACK_LOCATION IoStack;
+ PULONG HubCount;
+
+ DPRINT_IOCTL("USBH_PdoInternalControl: PortExtension - %p, Irp - %p\n",
+ PortExtension,
+ Irp);
+
+ HubExtension = PortExtension->HubExtension;
+
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED)
+ {
+ Status = STATUS_DEVICE_NOT_CONNECTED;
+ goto Exit;
+ }
+
+ if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD0)
+ {
+ Status = STATUS_DEVICE_POWERED_OFF;
+ goto Exit;
+ }
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
+
+ if (ControlCode == IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO)
+ {
+ HubExtension = PortExtension->RootHubExtension;
+ DPRINT("USBH_PdoInternalControl: HubExtension - %p\n", HubExtension);
+ }
+
+ if (!HubExtension)
+ {
+ Status = STATUS_DEVICE_BUSY;
+ goto Exit;
+ }
+
+ switch (ControlCode)
+ {
+ case IOCTL_INTERNAL_USB_SUBMIT_URB:
+ return USBH_PdoIoctlSubmitUrb(PortExtension, Irp);
+
+ case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n");
+ return USBH_PortIdleNotificationRequest(PortExtension, Irp);
+
+ case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
+ DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
+ return USBH_PdoIoctlGetPortStatus(PortExtension, Irp);
+
+ case IOCTL_INTERNAL_USB_RESET_PORT:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_RESET_PORT\n");
+ return USBH_PdoIoctlResetPort(PortExtension, Irp);
+
+ case IOCTL_INTERNAL_USB_ENABLE_PORT:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_ENABLE_PORT\n");
+ DbgBreakPoint();
+ break;
+
+ case IOCTL_INTERNAL_USB_CYCLE_PORT:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_CYCLE_PORT\n");
+ DbgBreakPoint();
+ break;
+
+ case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
+ DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
+ *(PVOID *)IoStack->Parameters.Others.Argument1 = PortExtension->DeviceHandle;
+ Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
+ DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_COUNT. PortPdoFlags - %lX\n",
+ PortExtension->PortPdoFlags);
+
+ if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ HubCount = IoStack->Parameters.Others.Argument1;
+
+ ++*HubCount;
+
+ Status = USBH_SyncGetHubCount(HubExtension->LowerDevice,
+ HubCount);
+
+ DPRINT("USBH_PdoInternalControl: *HubCount - %x\n", *HubCount);
+ break;
+
+ case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
+ DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO. PortPdoFlags - %lX\n",
+ PortExtension->PortPdoFlags);
+
+ if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE))
+ {
+ DbgBreakPoint();
+ Status = STATUS_SUCCESS;
+
+ *(PVOID *)IoStack->Parameters.Others.Argument1 = NULL;
+
+ USBH_CompleteIrp(Irp, Status);
+ break;
+ }
+
+ ASSERT(HubExtension->RootHubPdo);
+ return USBH_PassIrp(HubExtension->RootHubPdo, Irp);
+
+ case IOCTL_INTERNAL_USB_GET_HUB_NAME:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_NAME\n");
+ DbgBreakPoint();
+ break;
+
+ case IOCTL_GET_HCD_DRIVERKEY_NAME:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_GET_HCD_DRIVERKEY_NAME\n");
+ DbgBreakPoint();
+ break;
+
+ case IOCTL_INTERNAL_USB_GET_BUS_INFO:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_BUS_INFO\n");
+ DbgBreakPoint();
+ break;
+
+ case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
+ DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
+ DbgBreakPoint();
+ break;
+
+ default:
+ DPRINT1("USBH_PdoInternalControl: unhandled IOCTL_ - %lX\n", ControlCode);
+ break;
+ }
+
+Exit:
+ USBH_CompleteIrp(Irp, Status);
+ return Status;
+}