mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
2840 lines
85 KiB
C
2840 lines
85 KiB
C
/*
|
|
* PROJECT: ReactOS USB Hub Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: USBHub plug and play functions
|
|
* COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
|
|
*/
|
|
|
|
#include "usbhub.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define NDEBUG_USBHUB_PNP
|
|
#define NDEBUG_USBHUB_ENUM
|
|
#include "dbg_uhub.h"
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_IrpCompletion(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PRKEVENT Event;
|
|
|
|
DPRINT("USBH_IrpCompletion: Irp - %p\n", Irp);
|
|
|
|
Event = Context;
|
|
KeSetEvent(Event, EVENT_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_HubPnPIrpComplete(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
|
|
DPRINT("USBH_HubPnPIrpComplete: Irp - %p\n", Irp);
|
|
|
|
HubExtension = Context;
|
|
|
|
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
|
{
|
|
DPRINT1("USBH_HubPnPIrpComplete: Irp failed - %lX\n", Irp->IoStatus.Status);
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
KeSetEvent(&HubExtension->LowerDeviceEvent, EVENT_INCREMENT, FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_QueryCapsComplete(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PDEVICE_CAPABILITIES Capabilities;
|
|
|
|
DPRINT("USBH_QueryCapsComplete: ... \n");
|
|
|
|
ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
|
|
|
|
if (Irp->PendingReturned)
|
|
{
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
|
|
IoStack= IoGetCurrentIrpStackLocation(Irp);
|
|
Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
Capabilities->SurpriseRemovalOK = 1;
|
|
|
|
return STATUS_CONTINUE_COMPLETION;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBHUB_GetBusInterface(IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PUSB_BUS_INTERFACE_HUB_V5 BusInterface)
|
|
{
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
KEVENT Event;
|
|
|
|
DPRINT("USBHUB_GetBusInterface: ... \n");
|
|
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
|
|
if (!Irp)
|
|
{
|
|
DPRINT1("USBHUB_GetBusInterface: IoAllocateIrp() failed\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_IrpCompletion,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_PNP;
|
|
IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_HUB_GUID;
|
|
IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_HUB_V5);
|
|
IoStack->Parameters.QueryInterface.Version = USB_BUSIF_HUB_VERSION_5;
|
|
IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
|
|
IoStack->Parameters.QueryInterface.InterfaceSpecificData = DeviceObject;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBHUB_GetBusInterfaceUSBDI(IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterfaceUSBDI)
|
|
{
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
KEVENT Event;
|
|
|
|
DPRINT("USBHUB_GetBusInterfaceUSBDI: ... \n");
|
|
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
|
|
if (!Irp)
|
|
{
|
|
DPRINT1("USBHUB_GetBusInterfaceUSBDI: IoAllocateIrp() failed\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_IrpCompletion,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_PNP;
|
|
IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID;
|
|
IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V2);
|
|
IoStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_2;
|
|
IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterfaceUSBDI;
|
|
IoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_QueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDEVICE_CAPABILITIES DeviceCapabilities)
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
KEVENT Event;
|
|
|
|
DPRINT("USBH_QueryCapabilities: ... \n");
|
|
|
|
RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
|
|
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
|
|
if (!Irp)
|
|
{
|
|
DPRINT1("USBH_QueryCapabilities: IoAllocateIrp() failed\n");
|
|
return;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_IrpCompletion,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_PNP;
|
|
IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
|
|
|
|
IoStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
|
|
IoStack->Parameters.DeviceCapabilities.Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
|
|
IoStack->Parameters.DeviceCapabilities.Capabilities->Version = 1;
|
|
IoStack->Parameters.DeviceCapabilities.Capabilities->Address = MAXULONG;
|
|
IoStack->Parameters.DeviceCapabilities.Capabilities->UINumber = MAXULONG;
|
|
|
|
if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
IoFreeIrp(Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_OpenConfiguration(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_INTERFACE_DESCRIPTOR Pid;
|
|
PURB Urb;
|
|
NTSTATUS Status;
|
|
USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
|
|
|
|
DPRINT("USBH_OpenConfiguration ... \n");
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB &&
|
|
HubExtension->LowerPDO != HubExtension->RootHubPdo)
|
|
{
|
|
Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
|
|
HubExtension->HubConfigDescriptor,
|
|
-1,
|
|
-1,
|
|
USB_DEVICE_CLASS_HUB,
|
|
-1,
|
|
2);
|
|
|
|
if (Pid)
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_MULTIPLE_TTS;
|
|
}
|
|
else
|
|
{
|
|
Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
|
|
HubExtension->HubConfigDescriptor,
|
|
-1,
|
|
-1,
|
|
USB_DEVICE_CLASS_HUB,
|
|
-1,
|
|
1);
|
|
|
|
if (Pid)
|
|
{
|
|
goto Next;
|
|
}
|
|
|
|
Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
|
|
HubExtension->HubConfigDescriptor,
|
|
-1,
|
|
-1,
|
|
USB_DEVICE_CLASS_HUB,
|
|
-1,
|
|
0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
|
|
HubExtension->HubConfigDescriptor,
|
|
-1,
|
|
-1,
|
|
USB_DEVICE_CLASS_HUB,
|
|
-1,
|
|
-1);
|
|
}
|
|
|
|
if (!Pid)
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
Next:
|
|
|
|
if (Pid->bInterfaceClass != USB_DEVICE_CLASS_HUB)
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
InterfaceList[0].InterfaceDescriptor = Pid;
|
|
|
|
Urb = USBD_CreateConfigurationRequestEx(HubExtension->HubConfigDescriptor,
|
|
InterfaceList);
|
|
|
|
if (!Urb)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, Urb);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
RtlCopyMemory(&HubExtension->PipeInfo,
|
|
InterfaceList[0].Interface->Pipes,
|
|
sizeof(USBD_PIPE_INFORMATION));
|
|
|
|
HubExtension->ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
|
|
}
|
|
|
|
ExFreePool(Urb);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_Initialize20Hub(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_BUSIFFN_INITIALIZE_20HUB Initialize20Hub;
|
|
ULONG TtCount;
|
|
PUSB_DEVICE_HANDLE DeviceHandle;
|
|
|
|
DPRINT("USBD_InitUsb2Hub ... \n");
|
|
|
|
Initialize20Hub = HubExtension->BusInterface.Initialize20Hub;
|
|
|
|
if (!Initialize20Hub)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
TtCount = 1;
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_MULTIPLE_TTS)
|
|
{
|
|
TtCount = HubExtension->HubDescriptor->bNumberOfPorts;
|
|
}
|
|
|
|
DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
|
|
|
|
return Initialize20Hub(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle,
|
|
TtCount);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_AbortInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
struct _URB_PIPE_REQUEST * Urb;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_AbortInterruptPipe: HubExtension - %p\n", HubExtension);
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_PIPE_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (!Urb)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
|
|
Urb->Hdr.Function = URB_FUNCTION_ABORT_PIPE;
|
|
Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
|
|
|
|
Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
|
|
(PURB)Urb);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_FdoCleanup(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PIRP IdleIrp = NULL;
|
|
PIRP WakeIrp = NULL;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PIRP PortIdleIrp = NULL;
|
|
PIRP PortWakeIrp = NULL;
|
|
PVOID DeviceHandle;
|
|
NTSTATUS Status;
|
|
USHORT Port;
|
|
UCHAR NumberPorts;
|
|
KIRQL Irql;
|
|
|
|
DPRINT("USBH_FdoCleanup: HubExtension - %p\n", HubExtension);
|
|
|
|
USBD_UnRegisterRootHubCallBack(HubExtension);
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STOPPING;
|
|
|
|
if (HubExtension->ResetRequestCount)
|
|
{
|
|
IoCancelIrp(HubExtension->ResetPortIrp);
|
|
|
|
KeWaitForSingleObject(&HubExtension->IdleEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
IoFreeIrp(HubExtension->ResetPortIrp);
|
|
|
|
HubExtension->ResetPortIrp = NULL;
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->IdleEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
if (HubExtension->PendingWakeIrp)
|
|
{
|
|
WakeIrp = HubExtension->PendingWakeIrp;
|
|
HubExtension->PendingWakeIrp = NULL;
|
|
}
|
|
|
|
if (HubExtension->PendingIdleIrp)
|
|
{
|
|
IdleIrp = HubExtension->PendingIdleIrp;
|
|
HubExtension->PendingIdleIrp = NULL;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
if (WakeIrp)
|
|
{
|
|
USBH_HubCancelWakeIrp(HubExtension, WakeIrp);
|
|
}
|
|
|
|
USBH_HubCompletePortWakeIrps(HubExtension, STATUS_DELETE_PENDING);
|
|
|
|
if (IdleIrp)
|
|
{
|
|
USBH_HubCancelIdleIrp(HubExtension, IdleIrp);
|
|
}
|
|
|
|
if (InterlockedDecrement(&HubExtension->PendingRequestCount) > 0)
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->PendingRequestEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
if (HubExtension->SCEIrp)
|
|
{
|
|
Status = USBH_AbortInterruptPipe(HubExtension);
|
|
|
|
if (!NT_SUCCESS(Status) && IoCancelIrp(HubExtension->SCEIrp))
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
IoFreeIrp(HubExtension->SCEIrp);
|
|
|
|
HubExtension->SCEIrp = NULL;
|
|
}
|
|
|
|
if (!HubExtension->PortData ||
|
|
!HubExtension->HubDescriptor)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
PortData = HubExtension->PortData;
|
|
NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
|
|
|
|
for (Port = 0; Port < NumberPorts; Port++)
|
|
{
|
|
if (PortData[Port].DeviceObject)
|
|
{
|
|
PortExtension = PortData[Port].DeviceObject->DeviceExtension;
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
PortIdleIrp = PortExtension->IdleNotificationIrp;
|
|
|
|
if (PortIdleIrp)
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
|
|
PortExtension->IdleNotificationIrp = NULL;
|
|
|
|
if (PortIdleIrp->Cancel)
|
|
{
|
|
PortIdleIrp = NULL;
|
|
}
|
|
|
|
if (PortIdleIrp)
|
|
{
|
|
IoSetCancelRoutine(PortIdleIrp, NULL);
|
|
}
|
|
}
|
|
|
|
PortWakeIrp = PortExtension->PdoWaitWakeIrp;
|
|
|
|
if (PortWakeIrp)
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE;
|
|
PortExtension->PdoWaitWakeIrp = NULL;
|
|
|
|
if (PortWakeIrp->Cancel || !IoSetCancelRoutine(PortWakeIrp, NULL))
|
|
{
|
|
PortWakeIrp = NULL;
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
if (PortIdleIrp)
|
|
{
|
|
PortIdleIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
IoCompleteRequest(PortIdleIrp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
if (PortWakeIrp)
|
|
{
|
|
USBH_CompletePowerIrp(HubExtension,
|
|
PortWakeIrp,
|
|
STATUS_CANCELLED);
|
|
}
|
|
|
|
if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3))
|
|
{
|
|
DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
|
|
NULL);
|
|
|
|
if (DeviceHandle)
|
|
{
|
|
USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
|
|
}
|
|
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3;
|
|
}
|
|
}
|
|
|
|
USBH_SyncDisablePort(HubExtension, Port + 1);
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (HubExtension->SCEBitmap)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->SCEBitmap, USB_HUB_TAG);
|
|
}
|
|
|
|
if (HubExtension->HubDescriptor)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->HubDescriptor, USB_HUB_TAG);
|
|
}
|
|
|
|
if (HubExtension->HubConfigDescriptor)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->HubConfigDescriptor, USB_HUB_TAG);
|
|
}
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEVICE_STARTED;
|
|
|
|
HubExtension->HubDescriptor = NULL;
|
|
HubExtension->HubConfigDescriptor = NULL;
|
|
|
|
HubExtension->SCEIrp = NULL;
|
|
HubExtension->SCEBitmap = NULL;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_StartHubFdoDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG DisableRemoteWakeup = 0;
|
|
ULONG HubCount = 0;
|
|
PUSB_DEVICE_HANDLE DeviceHandle;
|
|
USB_DEVICE_TYPE DeviceType;
|
|
DEVICE_CAPABILITIES DeviceCapabilities;
|
|
BOOLEAN IsBusPowered;
|
|
static WCHAR DisableWakeValueName[] = L"DisableRemoteWakeup";
|
|
|
|
DPRINT("USBH_StartHubFdoDevice: ... \n");
|
|
|
|
KeInitializeEvent(&HubExtension->IdleEvent, NotificationEvent, FALSE);
|
|
KeInitializeEvent(&HubExtension->ResetEvent, NotificationEvent, TRUE);
|
|
KeInitializeEvent(&HubExtension->PendingRequestEvent, NotificationEvent, FALSE);
|
|
KeInitializeEvent(&HubExtension->LowerDeviceEvent, NotificationEvent, FALSE);
|
|
KeInitializeEvent(&HubExtension->StatusChangeEvent, NotificationEvent, TRUE);
|
|
KeInitializeEvent(&HubExtension->RootHubNotificationEvent,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
KeInitializeSpinLock(&HubExtension->RelationsWorkerSpinLock);
|
|
KeInitializeSpinLock(&HubExtension->CheckIdleSpinLock);
|
|
|
|
KeInitializeSemaphore(&HubExtension->ResetDeviceSemaphore, 1, 1);
|
|
KeInitializeSemaphore(&HubExtension->HubPortSemaphore, 1, 1);
|
|
KeInitializeSemaphore(&HubExtension->HubSemaphore, 1, 1);
|
|
|
|
HubExtension->HubFlags = 0;
|
|
HubExtension->HubConfigDescriptor = NULL;
|
|
HubExtension->HubDescriptor = NULL;
|
|
HubExtension->SCEIrp = NULL;
|
|
HubExtension->SCEBitmap = NULL;
|
|
HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
|
|
HubExtension->PendingRequestCount = 1;
|
|
HubExtension->ResetRequestCount = 0;
|
|
HubExtension->PendingIdleIrp = NULL;
|
|
HubExtension->PendingWakeIrp = NULL;
|
|
|
|
InitializeListHead(&HubExtension->PdoList);
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_WITEM_INIT;
|
|
InitializeListHead(&HubExtension->WorkItemList);
|
|
KeInitializeSpinLock(&HubExtension->WorkItemSpinLock);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_HubPnPIrpComplete,
|
|
HubExtension,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
if (IoCallDriver(HubExtension->LowerDevice, Irp) == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->LowerDeviceEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
HubExtension->RootHubPdo = NULL;
|
|
|
|
Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice,
|
|
&HubExtension->RootHubPdo,
|
|
&HubExtension->RootHubPdo2);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_SyncGetRootHubPdo() failed - %lX\n", Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
USBH_WriteFailReasonID(HubExtension->LowerPDO, USBHUB_FAIL_NO_FAIL);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBHUB_FDO_FLAG_DEVICE_FAILED - TRUE\n");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_REMOTE_WAKEUP;
|
|
|
|
Status = USBD_GetPdoRegistryParameter(HubExtension->LowerPDO,
|
|
&DisableRemoteWakeup,
|
|
sizeof(DisableRemoteWakeup),
|
|
DisableWakeValueName,
|
|
sizeof(DisableWakeValueName));
|
|
|
|
if (NT_SUCCESS(Status) && DisableRemoteWakeup)
|
|
{
|
|
DPRINT("USBH_StartHubFdoDevice: DisableRemoteWakeup - TRUE\n");
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_REMOTE_WAKEUP;
|
|
}
|
|
|
|
HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
|
|
|
|
USBH_SyncGetHubCount(HubExtension->LowerDevice,
|
|
&HubCount);
|
|
|
|
Status = USBHUB_GetBusInterface(HubExtension->RootHubPdo,
|
|
&HubExtension->BusInterface);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterface() failed - %lX\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBHUB_GetBusInterfaceUSBDI(HubExtension->LowerDevice,
|
|
&HubExtension->BusInterfaceUSBDI);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterfaceUSBDI() failed - %lX\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
|
|
|
|
if (DeviceHandle)
|
|
{
|
|
Status = USBH_GetDeviceType(HubExtension, DeviceHandle, &DeviceType);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceType() failed - %lX\n",
|
|
Status);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (DeviceType == Usb20Device)
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_USB20_HUB;
|
|
}
|
|
}
|
|
|
|
if (HubCount > USBHUB_MAX_CASCADE_LEVELS)
|
|
{
|
|
PUSBHUB_PORT_PDO_EXTENSION ParentPdoExtension;
|
|
PUSBHUB_FDO_EXTENSION ParentHubExtension;
|
|
USHORT ParentPort;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
|
|
DPRINT1("USBH_StartHubFdoDevice: HubCount > 6 - %x\n", HubCount);
|
|
|
|
USBH_WriteFailReasonID(HubExtension->LowerPDO,
|
|
USBHUB_FAIL_NESTED_TOO_DEEPLY);
|
|
|
|
ParentPdoExtension = HubExtension->LowerPDO->DeviceExtension;
|
|
ParentHubExtension = ParentPdoExtension->HubExtension;
|
|
|
|
ParentPort = ParentPdoExtension->PortNumber - 1;
|
|
PortData = &ParentHubExtension->PortData[ParentPort];
|
|
PortData->ConnectionStatus = DeviceHubNestedTooDeeply;
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
|
|
}
|
|
|
|
USBH_QueryCapabilities(HubExtension->LowerDevice, &DeviceCapabilities);
|
|
|
|
HubExtension->SystemWake = DeviceCapabilities.SystemWake;
|
|
HubExtension->DeviceWake = DeviceCapabilities.DeviceWake;
|
|
|
|
RtlCopyMemory(HubExtension->DeviceState,
|
|
&DeviceCapabilities.DeviceState,
|
|
POWER_SYSTEM_MAXIMUM * sizeof(DEVICE_POWER_STATE));
|
|
|
|
Status = USBH_GetDeviceDescriptor(HubExtension->Common.SelfDevice,
|
|
&HubExtension->HubDeviceDescriptor);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceDescriptor() failed - %lX\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBH_GetConfigurationDescriptor(HubExtension->Common.SelfDevice,
|
|
&HubExtension->HubConfigDescriptor);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBH_GetConfigurationDescriptor() failed - %lX\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBH_SyncGetHubDescriptor(HubExtension);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBH_SyncGetHubDescriptor() failed - %lX\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
IsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice,
|
|
HubExtension->HubConfigDescriptor);
|
|
|
|
if (IsBusPowered)
|
|
{
|
|
/* bus-powered hub is allowed a maximum of 100 mA only for each port */
|
|
HubExtension->MaxPowerPerPort = 100;
|
|
|
|
/* can have 4 ports (4 * 100 mA) and 100 mA remains for itself;
|
|
expressed in 2 mA units (i.e., 250 = 500 mA). */
|
|
HubExtension->HubConfigDescriptor->MaxPower = 250;
|
|
}
|
|
else
|
|
{
|
|
/* self-powered hub is allowed a maximum of 500 mA for each port */
|
|
HubExtension->MaxPowerPerPort = 500;
|
|
}
|
|
|
|
Status = USBH_OpenConfiguration(HubExtension);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_StartHubFdoDevice: USBH_OpenConfiguration() failed - %lX\n",
|
|
Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
|
|
{
|
|
Status = USBD_Initialize20Hub(HubExtension);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
HubExtension->SCEIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize,
|
|
FALSE);
|
|
|
|
HubExtension->ResetPortIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize,
|
|
FALSE);
|
|
|
|
if (!HubExtension->SCEIrp || !HubExtension->ResetPortIrp)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
HubExtension->SCEBitmapLength = HubExtension->PipeInfo.MaximumPacketSize;
|
|
|
|
HubExtension->SCEBitmap = ExAllocatePoolWithTag(NonPagedPool,
|
|
HubExtension->SCEBitmapLength,
|
|
USB_HUB_TAG);
|
|
|
|
if (!HubExtension->SCEBitmap)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
RtlZeroMemory(HubExtension->SCEBitmap, HubExtension->SCEBitmapLength);
|
|
|
|
Status = USBH_SyncPowerOnPorts(HubExtension);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
else
|
|
{
|
|
USHORT Port;
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STARTED;
|
|
|
|
for (Port = 1;
|
|
Port <= HubExtension->HubDescriptor->bNumberOfPorts;
|
|
Port++)
|
|
{
|
|
USBH_SyncClearPortStatus(HubExtension,
|
|
Port,
|
|
USBHUB_FEATURE_C_PORT_CONNECTION);
|
|
}
|
|
}
|
|
|
|
if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
|
|
{
|
|
USBD_RegisterRootHubCallBack(HubExtension);
|
|
}
|
|
else
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
|
|
USBH_SubmitStatusChangeTransfer(HubExtension);
|
|
}
|
|
|
|
goto Exit;
|
|
|
|
ErrorExit:
|
|
|
|
if (HubExtension->HubDescriptor)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->HubDescriptor, USB_HUB_TAG);
|
|
HubExtension->HubDescriptor = NULL;
|
|
}
|
|
|
|
if (HubExtension->SCEIrp)
|
|
{
|
|
IoFreeIrp(HubExtension->SCEIrp);
|
|
HubExtension->SCEIrp = NULL;
|
|
}
|
|
|
|
if (HubExtension->ResetPortIrp)
|
|
{
|
|
IoFreeIrp(HubExtension->ResetPortIrp);
|
|
HubExtension->ResetPortIrp = NULL;
|
|
}
|
|
|
|
if (HubExtension->SCEBitmap)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->SCEBitmap, USB_HUB_TAG);
|
|
HubExtension->SCEBitmap = NULL;
|
|
}
|
|
|
|
if (HubExtension->HubConfigDescriptor)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->HubConfigDescriptor, USB_HUB_TAG);
|
|
HubExtension->HubConfigDescriptor = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
USBH_CompleteIrp(Irp, Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoStartDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_FdoStartDevice: HubExtension - %p\n", HubExtension);
|
|
|
|
HubExtension->RootHubPdo = NULL;
|
|
|
|
Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice,
|
|
&HubExtension->RootHubPdo,
|
|
&HubExtension->RootHubPdo2);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (HubExtension->RootHubPdo)
|
|
{
|
|
Status = USBH_StartHubFdoDevice(HubExtension, Irp);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("USBH_FdoStartDevice: FIXME. start ParentDevice\n");
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("USBH_FdoStartDevice: FIXME. USBH_SyncGetRootHubPdo return - %lX\n",
|
|
Status);
|
|
|
|
DbgBreakPoint();
|
|
USBH_CompleteIrp(Irp, Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoQueryBusRelations(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PDEVICE_RELATIONS DeviceRelations = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
LIST_ENTRY GhostPdoList;
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY PdoList;
|
|
UCHAR NumberPorts;
|
|
USHORT Port;
|
|
USHORT GhostPort;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
PDEVICE_OBJECT PdoDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PdoExtension;
|
|
PUSBHUB_PORT_PDO_EXTENSION pdoExtension;
|
|
NTSTATUS NtStatus;
|
|
PVOID SerialNumber;
|
|
PVOID DeviceHandle;
|
|
USB_PORT_STATUS UsbPortStatus;
|
|
PLIST_ENTRY Entry;
|
|
ULONG Length;
|
|
|
|
DPRINT_ENUM("USBH_FdoQueryBusRelations: HubFlags - %lX\n",
|
|
HubExtension->HubFlags);
|
|
|
|
if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED))
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_STATE;
|
|
goto RelationsWorker;
|
|
}
|
|
|
|
if (!HubExtension->HubDescriptor)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto RelationsWorker;
|
|
}
|
|
|
|
if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
|
|
{
|
|
// FIXME: this delay makes devices discovery during early boot more reliable
|
|
LARGE_INTEGER Interval;
|
|
Status = STATUS_SUCCESS;
|
|
IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
|
|
Interval.QuadPart = -10000LL * 1000; // 1 sec.
|
|
KeDelayExecutionThread(KernelMode, FALSE, &Interval);
|
|
|
|
DPRINT_ENUM("USBH_FdoQueryBusRelations: Skip enumeration\n");
|
|
goto RelationsWorker;
|
|
}
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
|
|
DPRINT_ENUM("USBH_FdoQueryBusRelations: NumberPorts - %x\n", NumberPorts);
|
|
|
|
Length = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
|
|
NumberPorts * sizeof(PDEVICE_OBJECT);
|
|
|
|
if (Irp->IoStatus.Information)
|
|
{
|
|
DPRINT1("FIXME: leaking old bus relations\n");
|
|
}
|
|
|
|
DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!DeviceRelations)
|
|
{
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
|
|
}
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto RelationsWorker;
|
|
}
|
|
|
|
RtlZeroMemory(DeviceRelations, Length);
|
|
|
|
DeviceRelations->Count = 0;
|
|
|
|
EnumStart:
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
|
|
{
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto RelationsWorker;
|
|
}
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_ENUM_POST_RECOVER;
|
|
|
|
for (Port = 1; Port <= NumberPorts; Port++)
|
|
{
|
|
PortData = &HubExtension->PortData[Port - 1];
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortData->PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT_ENUM("USBH_FdoQueryBusRelations: Status - %X\n", Status);
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
|
|
DeviceRelations->Count = 0;
|
|
goto EnumStart;
|
|
}
|
|
|
|
DPRINT_ENUM("USBH_FdoQueryBusRelations: Port - %x, ConnectStatus - %x\n",
|
|
Port,
|
|
PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus);
|
|
|
|
PdoDevice = PortData->DeviceObject;
|
|
|
|
if (PortData->DeviceObject)
|
|
{
|
|
PdoExtension = PdoDevice->DeviceExtension;
|
|
|
|
if (PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
|
|
{
|
|
PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
|
|
}
|
|
}
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
|
|
{
|
|
DPRINT1("USBH_FdoQueryBusRelations: DbgBreakPoint() \n");
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
if (!PortData->PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
|
|
{
|
|
if (PdoDevice)
|
|
{
|
|
PdoExtension = PdoDevice->DeviceExtension;
|
|
|
|
PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING;
|
|
PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
|
|
|
|
SerialNumber = InterlockedExchangePointer((PVOID)&PdoExtension->SerialNumber,
|
|
NULL);
|
|
|
|
if (SerialNumber)
|
|
{
|
|
ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
|
|
}
|
|
|
|
DeviceHandle = InterlockedExchangePointer(&PdoExtension->DeviceHandle,
|
|
NULL);
|
|
|
|
if (DeviceHandle)
|
|
{
|
|
USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
|
|
USBH_SyncDisablePort(HubExtension, Port);
|
|
}
|
|
}
|
|
|
|
PortData->DeviceObject = NULL;
|
|
PortData->ConnectionStatus = NoDeviceConnected;
|
|
continue;
|
|
}
|
|
|
|
if (PdoDevice)
|
|
{
|
|
ObReferenceObject(PdoDevice);
|
|
|
|
PdoDevice->Flags |= DO_POWER_PAGABLE;
|
|
PdoDevice->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DeviceRelations->Objects[DeviceRelations->Count++] = PdoDevice;
|
|
|
|
PdoExtension = PdoDevice->DeviceExtension;
|
|
PdoExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D1_OR_D2;
|
|
|
|
continue;
|
|
}
|
|
|
|
USBH_Wait(100);
|
|
|
|
NtStatus = USBH_SyncResetPort(HubExtension, Port);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
|
|
{
|
|
PortData->DeviceObject = NULL;
|
|
PortData->ConnectionStatus = NoDeviceConnected;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NtStatus = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortData->PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
UsbPortStatus = PortData->PortStatus.PortStatus;
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
ULONG ix = 0;
|
|
|
|
for (NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix);
|
|
!NT_SUCCESS(NtStatus);
|
|
NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix))
|
|
{
|
|
USBH_Wait(500);
|
|
|
|
if (ix >= 2)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (PortData->DeviceObject)
|
|
{
|
|
IoDeleteDevice(PortData->DeviceObject);
|
|
PortData->DeviceObject = NULL;
|
|
PortData->ConnectionStatus = NoDeviceConnected;
|
|
}
|
|
|
|
USBH_SyncResetPort(HubExtension, Port);
|
|
|
|
ix++;
|
|
}
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
PdoExtension = PortData->DeviceObject->DeviceExtension;
|
|
|
|
if (!(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_LOW_SPEED) &&
|
|
!(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_HIGH_SPEED) &&
|
|
!(HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB))
|
|
{
|
|
DPRINT1("USBH_FdoQueryBusRelations: FIXME USBH_DeviceIs2xDualMode()\n");
|
|
|
|
if (0)//USBH_DeviceIs2xDualMode(PdoExtension))
|
|
{
|
|
PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_HS_USB1_DUALMODE;
|
|
}
|
|
}
|
|
|
|
ObReferenceObject(PortData->DeviceObject);
|
|
|
|
DeviceRelations->Objects[DeviceRelations->Count] = PortData->DeviceObject;
|
|
|
|
PortData->DeviceObject->Flags |= DO_POWER_PAGABLE;
|
|
PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DeviceRelations->Count++;
|
|
|
|
PortData->ConnectionStatus = DeviceConnected;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
PortData->ConnectionStatus = DeviceFailedEnumeration;
|
|
|
|
if (NT_ERROR(USBH_SyncDisablePort(HubExtension, Port)))
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
|
|
}
|
|
|
|
if (PortData->DeviceObject)
|
|
{
|
|
ObReferenceObject(PortData->DeviceObject);
|
|
PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
DeviceRelations->Objects[DeviceRelations->Count++] = PortData->DeviceObject;
|
|
}
|
|
}
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
|
|
}
|
|
|
|
RelationsWorker:
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//Irp->IoStatus.Information = 0;
|
|
|
|
if (DeviceRelations)
|
|
{
|
|
ExFreePoolWithTag(DeviceRelations, USB_HUB_TAG);
|
|
}
|
|
|
|
USBH_CompleteIrp(Irp, Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &OldIrql);
|
|
|
|
if (DeviceRelations && DeviceRelations->Count)
|
|
{
|
|
for (Port = 0; Port < DeviceRelations->Count; Port++)
|
|
{
|
|
PdoDevice = DeviceRelations->Objects[Port];
|
|
Entry = HubExtension->PdoList.Flink;
|
|
|
|
while (Entry != &HubExtension->PdoList)
|
|
{
|
|
pdoExtension = CONTAINING_RECORD(Entry,
|
|
USBHUB_PORT_PDO_EXTENSION,
|
|
PortLink);
|
|
|
|
if (pdoExtension == PdoDevice->DeviceExtension)
|
|
{
|
|
PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_GHOST_DEVICE;
|
|
goto PortNext;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_DEVICE_PRESENT;
|
|
|
|
PortNext:;
|
|
}
|
|
|
|
for (Port = 0; Port < DeviceRelations->Count; Port++)
|
|
{
|
|
PdoDevice = DeviceRelations->Objects[Port];
|
|
|
|
if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE)
|
|
{
|
|
for (GhostPort = Port;
|
|
GhostPort < DeviceRelations->Count;
|
|
GhostPort++)
|
|
{
|
|
DeviceRelations->Objects[GhostPort] =
|
|
DeviceRelations->Objects[GhostPort + 1];
|
|
}
|
|
|
|
ObDereferenceObject(PdoDevice);
|
|
|
|
DeviceRelations->Count--;
|
|
|
|
if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)
|
|
{
|
|
PdoExt(PdoDevice)->EnumFlags &= ~USBHUB_ENUM_FLAG_GHOST_DEVICE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
|
|
InitializeListHead(&GhostPdoList);
|
|
PdoList = &HubExtension->PdoList;
|
|
|
|
while (!IsListEmpty(PdoList))
|
|
{
|
|
Entry = RemoveHeadList(PdoList);
|
|
|
|
PdoExtension = CONTAINING_RECORD(Entry,
|
|
USBHUB_PORT_PDO_EXTENSION,
|
|
PortLink);
|
|
|
|
PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
|
|
|
|
if (PdoExtension->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE)
|
|
{
|
|
InsertTailList(&GhostPdoList, &PdoExtension->PortLink);
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, OldIrql);
|
|
|
|
while (!IsListEmpty(&GhostPdoList))
|
|
{
|
|
Entry = RemoveHeadList(&GhostPdoList);
|
|
|
|
PdoExtension = CONTAINING_RECORD(Entry,
|
|
USBHUB_PORT_PDO_EXTENSION,
|
|
PortLink);
|
|
|
|
IoDeleteDevice(PdoExtension->Common.SelfDevice);
|
|
}
|
|
|
|
return USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoStopDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT1("USBH_FdoStopDevice: UNIMPLEMENTED. FIXME\n");
|
|
DbgBreakPoint();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PUSB_HUB_DESCRIPTOR HubDescriptor;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
USHORT NumPorts;
|
|
USHORT ix;
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_FdoRemoveDevice: HubExtension - %p\n", HubExtension);
|
|
|
|
HubDescriptor = HubExtension->HubDescriptor;
|
|
|
|
if (HubDescriptor && HubExtension->PortData)
|
|
{
|
|
NumPorts = HubDescriptor->bNumberOfPorts;
|
|
|
|
for (ix = 0; ix < NumPorts; ++ix)
|
|
{
|
|
PortData = HubExtension->PortData + ix;
|
|
|
|
PortDevice = PortData->DeviceObject;
|
|
|
|
if (PortDevice)
|
|
{
|
|
PortData->PortStatus.AsUlong32 = 0;
|
|
PortData->DeviceObject = NULL;
|
|
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
|
|
|
|
USBH_PdoRemoveDevice(PortExtension, HubExtension);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
|
|
{
|
|
USBH_FdoCleanup(HubExtension);
|
|
}
|
|
|
|
if (HubExtension->PortData)
|
|
{
|
|
ExFreePoolWithTag(HubExtension->PortData, USB_HUB_TAG);
|
|
HubExtension->PortData = NULL;
|
|
}
|
|
|
|
DPRINT1("USBH_FdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
|
|
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
|
|
IoDetachDevice(HubExtension->LowerDevice);
|
|
IoDeleteDevice(HubExtension->Common.SelfDevice);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_FdoSurpriseRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
ULONG NumberPorts;
|
|
ULONG Port;
|
|
|
|
DPRINT("USBH_FdoSurpriseRemoveDevice: HubExtension - %p, Irp - %p\n",
|
|
HubExtension,
|
|
Irp);
|
|
|
|
if (!HubExtension->PortData ||
|
|
!HubExtension->HubDescriptor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PortData = HubExtension->PortData;
|
|
NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
|
|
|
|
for (Port = 0; Port < NumberPorts; Port++)
|
|
{
|
|
if (PortData[Port].DeviceObject)
|
|
{
|
|
PortExtension = PdoExt(PortData[Port].DeviceObject);
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING;
|
|
PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
|
|
|
|
PortData[Port].DeviceObject = NULL;
|
|
PortData[Port].ConnectionStatus = NoDeviceConnected;
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
ULONG IdType;
|
|
WCHAR Buffer[200];
|
|
PWCHAR EndBuffer;
|
|
size_t Remaining = sizeof(Buffer);
|
|
size_t Length;
|
|
PWCHAR Id = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
|
|
|
|
IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
|
|
DeviceDescriptor = &PortExtension->DeviceDescriptor;
|
|
InterfaceDescriptor = &PortExtension->InterfaceDescriptor;
|
|
|
|
RtlZeroMemory(Buffer, sizeof(Buffer));
|
|
|
|
switch (IdType)
|
|
{
|
|
case BusQueryDeviceID:
|
|
DPRINT("USBH_PdoQueryId: BusQueryDeviceID\n");
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
|
|
{
|
|
DPRINT("USBH_PdoQueryId: USBHUB_PDO_FLAG_INIT_PORT_FAILED\n");
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Vid_0000&Pid_0000");
|
|
}
|
|
else
|
|
{
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Vid_%04x&Pid_%04x",
|
|
DeviceDescriptor->idVendor,
|
|
DeviceDescriptor->idProduct);
|
|
}
|
|
|
|
Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL));
|
|
|
|
Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!Id)
|
|
{
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(Id, Buffer, Length);
|
|
DPRINT("USBH_PdoQueryId: BusQueryDeviceID - %S\n", Id);
|
|
break;
|
|
|
|
case BusQueryHardwareIDs:
|
|
DPRINT("USBH_PdoQueryId: BusQueryHardwareIDs\n");
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
|
|
{
|
|
DPRINT("USBH_PdoQueryId: USBHUB_PDO_FLAG_INIT_PORT_FAILED\n");
|
|
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\UNKNOWN");
|
|
}
|
|
else
|
|
{
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
&EndBuffer,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
|
|
DeviceDescriptor->idVendor,
|
|
DeviceDescriptor->idProduct,
|
|
DeviceDescriptor->bcdDevice);
|
|
|
|
EndBuffer++;
|
|
Remaining -= sizeof(UNICODE_NULL);
|
|
|
|
RtlStringCbPrintfExW(EndBuffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Vid_%04x&Pid_%04x",
|
|
DeviceDescriptor->idVendor,
|
|
DeviceDescriptor->idProduct);
|
|
}
|
|
|
|
Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL));
|
|
|
|
Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!Id)
|
|
{
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(Id, Buffer, Length);
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
|
|
{
|
|
DPRINT("USBH_PdoQueryId: BusQueryHardwareID - %S\n", Id);
|
|
}
|
|
else
|
|
{
|
|
USBHUB_DumpingIDs(Id);
|
|
}
|
|
|
|
break;
|
|
|
|
case BusQueryCompatibleIDs:
|
|
DPRINT("USBH_PdoQueryId: BusQueryCompatibleIDs\n");
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
|
|
{
|
|
DPRINT("USBH_PdoQueryId: USBHUB_PDO_FLAG_INIT_PORT_FAILED\n");
|
|
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\UNKNOWN");
|
|
}
|
|
else if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_MULTI_INTERFACE)
|
|
{
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
&EndBuffer,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
|
|
InterfaceDescriptor->bInterfaceClass,
|
|
InterfaceDescriptor->bInterfaceSubClass,
|
|
InterfaceDescriptor->bInterfaceProtocol);
|
|
|
|
EndBuffer++;
|
|
Remaining -= sizeof(UNICODE_NULL);
|
|
|
|
RtlStringCbPrintfExW(EndBuffer,
|
|
Remaining,
|
|
&EndBuffer,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\DevClass_%02x&SubClass_%02x",
|
|
InterfaceDescriptor->bInterfaceClass,
|
|
InterfaceDescriptor->bInterfaceSubClass);
|
|
|
|
EndBuffer++;
|
|
Remaining -= sizeof(UNICODE_NULL);
|
|
|
|
RtlStringCbPrintfExW(EndBuffer,
|
|
Remaining,
|
|
&EndBuffer,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\DevClass_%02x",
|
|
InterfaceDescriptor->bInterfaceClass);
|
|
|
|
EndBuffer++;
|
|
Remaining -= sizeof(UNICODE_NULL);
|
|
|
|
RtlStringCbPrintfExW(EndBuffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\COMPOSITE");
|
|
}
|
|
else
|
|
{
|
|
RtlStringCbPrintfExW(Buffer,
|
|
Remaining,
|
|
&EndBuffer,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
|
|
InterfaceDescriptor->bInterfaceClass,
|
|
InterfaceDescriptor->bInterfaceSubClass,
|
|
InterfaceDescriptor->bInterfaceProtocol);
|
|
|
|
EndBuffer++;
|
|
Remaining -= sizeof(UNICODE_NULL);
|
|
|
|
RtlStringCbPrintfExW(EndBuffer,
|
|
Remaining,
|
|
&EndBuffer,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Class_%02x&SubClass_%02x",
|
|
InterfaceDescriptor->bInterfaceClass,
|
|
InterfaceDescriptor->bInterfaceSubClass);
|
|
|
|
EndBuffer++;
|
|
Remaining -= sizeof(UNICODE_NULL);
|
|
|
|
RtlStringCbPrintfExW(EndBuffer,
|
|
Remaining,
|
|
NULL,
|
|
&Remaining,
|
|
0,
|
|
L"USB\\Class_%02x",
|
|
InterfaceDescriptor->bInterfaceClass);
|
|
}
|
|
|
|
Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL));
|
|
|
|
Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!Id)
|
|
{
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(Id, Buffer, Length);
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
|
|
{
|
|
DPRINT("USBH_PdoQueryId: BusQueryCompatibleID - %S\n", Id);
|
|
}
|
|
else
|
|
{
|
|
USBHUB_DumpingIDs(Id);
|
|
}
|
|
|
|
break;
|
|
|
|
case BusQueryInstanceID:
|
|
DPRINT("USBH_PdoQueryId: BusQueryInstanceID\n");
|
|
|
|
if (PortExtension->SerialNumber)
|
|
{
|
|
Id = ExAllocatePoolWithTag(PagedPool,
|
|
PortExtension->SN_DescriptorLength,
|
|
USB_HUB_TAG);
|
|
|
|
if (Id)
|
|
{
|
|
RtlZeroMemory(Id, PortExtension->SN_DescriptorLength);
|
|
|
|
RtlCopyMemory(Id,
|
|
PortExtension->SerialNumber,
|
|
PortExtension->SN_DescriptorLength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Length = sizeof(PortExtension->InstanceID) +
|
|
sizeof(UNICODE_NULL);
|
|
|
|
Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (Id)
|
|
{
|
|
RtlZeroMemory(Id, Length);
|
|
|
|
RtlCopyMemory(Id,
|
|
PortExtension->InstanceID,
|
|
sizeof(PortExtension->InstanceID));
|
|
}
|
|
}
|
|
|
|
DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("USBH_PdoQueryId: unknown query id type 0x%lx\n", IdType);
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)Id;
|
|
|
|
if (!Id)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoQueryDeviceText(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PIO_STACK_LOCATION IoStack;
|
|
DEVICE_TEXT_TYPE DeviceTextType;
|
|
USHORT LanguageId;
|
|
USHORT DefaultId;
|
|
PUSB_STRING_DESCRIPTOR Descriptor;
|
|
PWCHAR DeviceText;
|
|
UCHAR iProduct = 0;
|
|
NTSTATUS Status;
|
|
size_t NumSymbols;
|
|
size_t Length;
|
|
|
|
DPRINT("USBH_PdoQueryDeviceText ... \n");
|
|
|
|
DeviceObject = PortExtension->Common.SelfDevice;
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
DeviceTextType = IoStack->Parameters.QueryDeviceText.DeviceTextType;
|
|
|
|
if (DeviceTextType != DeviceTextDescription &&
|
|
DeviceTextType != DeviceTextLocationInformation)
|
|
{
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
LanguageId = LANGIDFROMLCID(IoStack->Parameters.QueryDeviceText.LocaleId);
|
|
DefaultId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|
|
|
if (!LanguageId)
|
|
{
|
|
LanguageId = DefaultId;
|
|
}
|
|
|
|
iProduct = PortExtension->DeviceDescriptor.iProduct;
|
|
|
|
if (PortExtension->DeviceHandle && iProduct &&
|
|
!PortExtension->IgnoringHwSerial &&
|
|
!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED))
|
|
{
|
|
Descriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
MAXIMUM_USB_STRING_LENGTH,
|
|
USB_HUB_TAG);
|
|
|
|
if (Descriptor)
|
|
{
|
|
RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
|
|
|
|
for (Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
|
|
;
|
|
Status = USBH_CheckDeviceLanguage(DeviceObject, DefaultId))
|
|
{
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = USBH_SyncGetStringDescriptor(DeviceObject,
|
|
iProduct,
|
|
LanguageId,
|
|
Descriptor,
|
|
MAXIMUM_USB_STRING_LENGTH,
|
|
NULL,
|
|
TRUE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (LanguageId == DefaultId)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
LanguageId = DefaultId;
|
|
}
|
|
|
|
if (Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Length = Descriptor->bLength -
|
|
FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
|
|
|
|
DeviceText = ExAllocatePoolWithTag(PagedPool,
|
|
Length + sizeof(UNICODE_NULL),
|
|
USB_HUB_TAG);
|
|
|
|
if (DeviceText)
|
|
{
|
|
RtlZeroMemory(DeviceText, Length + sizeof(UNICODE_NULL));
|
|
|
|
RtlCopyMemory(DeviceText, Descriptor->bString, Length);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceText;
|
|
|
|
DPRINT("USBH_PdoQueryDeviceText: Descriptor->bString - %S\n",
|
|
DeviceText);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (!GenericUSBDeviceString)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
NumSymbols = wcslen(GenericUSBDeviceString);
|
|
Length = (NumSymbols + 1) * sizeof(WCHAR);
|
|
|
|
DeviceText = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!DeviceText)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(DeviceText, Length);
|
|
|
|
RtlCopyMemory(DeviceText,
|
|
GenericUSBDeviceString,
|
|
NumSymbols * sizeof(WCHAR));
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceText;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SymbolicLink(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN const GUID * InterfaceClassGuid,
|
|
IN BOOLEAN IsEnable)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PVOID NameBuffer;
|
|
|
|
DPRINT("USBH_SymbolicLink ... \n");
|
|
|
|
if (IsEnable)
|
|
{
|
|
Status = IoRegisterDeviceInterface(PortExtension->Common.SelfDevice,
|
|
InterfaceClassGuid,
|
|
NULL,
|
|
&PortExtension->SymbolicLinkName);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
USBH_SetPdoRegistryParameter(PortExtension->Common.SelfDevice,
|
|
L"SymbolicName",
|
|
PortExtension->SymbolicLinkName.Buffer,
|
|
PortExtension->SymbolicLinkName.Length,
|
|
REG_SZ,
|
|
PLUGPLAY_REGKEY_DEVICE);
|
|
|
|
Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName,
|
|
TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NameBuffer = PortExtension->SymbolicLinkName.Buffer;
|
|
|
|
if (NameBuffer)
|
|
{
|
|
Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName,
|
|
FALSE);
|
|
|
|
ExFreePool(PortExtension->SymbolicLinkName.Buffer);
|
|
|
|
PortExtension->SymbolicLinkName.Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_RestoreDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN BOOLEAN IsKeepDeviceData)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
NTSTATUS Status;
|
|
ULONG ix;
|
|
|
|
DPRINT("USBH_RestoreDevice ... \n");
|
|
|
|
HubExtension = PortExtension->HubExtension;
|
|
|
|
if (!HubExtension)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
return Status;
|
|
}
|
|
|
|
ASSERT(PortExtension->PortNumber > 0);
|
|
PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
|
|
|
|
if (PortExtension->Common.SelfDevice != PortData->DeviceObject)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
return Status;
|
|
}
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
PortExtension->PortNumber,
|
|
&PortData->PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
for (ix = 0; ix < 3; ix++)
|
|
{
|
|
Status = USBH_ResetDevice((PUSBHUB_FDO_EXTENSION)HubExtension,
|
|
PortExtension->PortNumber,
|
|
IsKeepDeviceData,
|
|
ix == 0);
|
|
|
|
if (NT_SUCCESS(Status) || Status == STATUS_NO_SUCH_DEVICE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
USBH_Wait(1000);
|
|
}
|
|
}
|
|
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D3;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL;
|
|
}
|
|
else
|
|
{
|
|
PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_INIT_PORT_FAILED |
|
|
USBHUB_PDO_FLAG_PORT_RESTORE_FAIL);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoStartDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
const GUID * Guid;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_PdoStartDevice: PortExtension - %p\n", PortExtension);
|
|
|
|
if (!PortExtension->HubExtension &&
|
|
PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
|
|
{
|
|
PortExtension->HubExtension = PortExtension->RootHubExtension;
|
|
}
|
|
|
|
HubExtension = PortExtension->HubExtension;
|
|
|
|
if (HubExtension)
|
|
{
|
|
USBHUB_SetDeviceHandleData(HubExtension,
|
|
PortExtension->Common.SelfDevice,
|
|
PortExtension->DeviceHandle);
|
|
}
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE)
|
|
{
|
|
Guid = &GUID_DEVINTERFACE_USB_HUB;
|
|
}
|
|
else
|
|
{
|
|
Guid = &GUID_DEVINTERFACE_USB_DEVICE;
|
|
}
|
|
|
|
Status = USBH_SymbolicLink(PortExtension, Guid, TRUE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
|
|
}
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
|
|
{
|
|
Status = USBH_RestoreDevice(PortExtension, 0);
|
|
}
|
|
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DEVICE_STARTED;
|
|
|
|
PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
|
|
|
|
DPRINT1("USBH_PdoStartDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoRemoveDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExt;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
PIRP IdleNotificationIrp;
|
|
PIRP WakeIrp;
|
|
PVOID DeviceHandle;
|
|
PDEVICE_OBJECT Pdo;
|
|
PVOID SerialNumber;
|
|
USHORT Port;
|
|
KIRQL Irql;
|
|
|
|
DPRINT("USBH_PdoRemoveDevice ... \n");
|
|
|
|
PortDevice = PortExtension->Common.SelfDevice;
|
|
PortExtension->HubExtension = NULL;
|
|
|
|
Port = PortExtension->PortNumber;
|
|
ASSERT(Port > 0);
|
|
|
|
if (HubExtension &&
|
|
HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
|
|
(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) != 0)
|
|
{
|
|
USBH_HubSetD0(HubExtension);
|
|
}
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
IdleNotificationIrp = PortExtension->IdleNotificationIrp;
|
|
|
|
if (IdleNotificationIrp)
|
|
{
|
|
PortExtension->IdleNotificationIrp = NULL;
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
|
|
|
|
if (IdleNotificationIrp->Cancel)
|
|
{
|
|
IdleNotificationIrp = NULL;
|
|
}
|
|
|
|
if (IdleNotificationIrp)
|
|
{
|
|
IoSetCancelRoutine(IdleNotificationIrp, NULL);
|
|
}
|
|
}
|
|
|
|
WakeIrp = PortExtension->PdoWaitWakeIrp;
|
|
|
|
if (WakeIrp)
|
|
{
|
|
PortExtension->PdoWaitWakeIrp = NULL;
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE;
|
|
|
|
if (WakeIrp->Cancel || !IoSetCancelRoutine(WakeIrp, NULL))
|
|
{
|
|
WakeIrp = NULL;
|
|
|
|
ASSERT(HubExtension);
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
if (IdleNotificationIrp)
|
|
{
|
|
IdleNotificationIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
IoCompleteRequest(IdleNotificationIrp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
if (WakeIrp)
|
|
{
|
|
ASSERT(HubExtension);
|
|
USBH_CompletePowerIrp(HubExtension, WakeIrp, STATUS_CANCELLED);
|
|
}
|
|
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3;
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)
|
|
{
|
|
Status = USBH_SymbolicLink(PortExtension, NULL, FALSE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
|
|
}
|
|
}
|
|
|
|
DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
|
|
NULL);
|
|
|
|
if (DeviceHandle)
|
|
{
|
|
ASSERT(HubExtension);
|
|
Status = USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
|
|
|
|
if (HubExtension->PortData &&
|
|
HubExtension->PortData[Port - 1].DeviceObject == PortDevice)
|
|
{
|
|
USBH_SyncDisablePort(HubExtension, Port);
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_DEVICE_STARTED;
|
|
|
|
if (HubExtension && HubExtension->PortData)
|
|
{
|
|
PortData = &HubExtension->PortData[Port - 1];
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING)
|
|
{
|
|
Pdo = PortData->DeviceObject;
|
|
|
|
if (Pdo)
|
|
{
|
|
PortData->DeviceObject = NULL;
|
|
PortData->ConnectionStatus = NoDeviceConnected;
|
|
|
|
if (PdoExt(Pdo)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)
|
|
{
|
|
PortExt = PdoExt(Pdo);
|
|
|
|
InsertTailList(&HubExtension->PdoList,
|
|
&PortExt->PortLink);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(PortExtension->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT) &&
|
|
!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED))
|
|
{
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_NOT_CONNECTED;
|
|
|
|
SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
|
|
NULL);
|
|
|
|
if (SerialNumber)
|
|
{
|
|
ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
|
|
}
|
|
|
|
DPRINT1("USBH_PdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
|
|
|
|
if (HubExtension)
|
|
USBHUB_FlushAllTransfers(HubExtension);
|
|
|
|
IoDeleteDevice(PortDevice);
|
|
}
|
|
}
|
|
|
|
if (HubExtension)
|
|
{
|
|
DPRINT("USBH_PdoRemoveDevice: call USBH_CheckIdleDeferred()\n");
|
|
USBH_CheckIdleDeferred(HubExtension);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoStopDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT1("USBH_PdoStopDevice: UNIMPLEMENTED. FIXME\n");
|
|
DbgBreakPoint();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoPnP(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp,
|
|
IN UCHAR Minor)
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
DEVICE_RELATION_TYPE RelationsType;
|
|
BOOLEAN IsCheckIdle;
|
|
|
|
DPRINT_PNP("USBH_FdoPnP: HubExtension - %p, Irp - %p, Minor - %X\n",
|
|
HubExtension,
|
|
Irp,
|
|
Minor);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST &&
|
|
(Minor == IRP_MN_REMOVE_DEVICE || Minor == IRP_MN_STOP_DEVICE))
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED;
|
|
}
|
|
|
|
KeWaitForSingleObject(&HubExtension->IdleSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
DPRINT_PNP("USBH_FdoPnP: HubFlags - %lX\n", HubExtension->HubFlags);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_GOING_IDLE)
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED;
|
|
}
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
RelationsType = IoStack->Parameters.QueryDeviceRelations.Type;
|
|
|
|
if ((HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0) ||
|
|
!(HubExtension->HubFlags & (USBHUB_FDO_FLAG_DEVICE_STOPPED | USBHUB_FDO_FLAG_DEVICE_STARTED)) ||
|
|
(Minor == IRP_MN_QUERY_DEVICE_RELATIONS && RelationsType == TargetDeviceRelation))
|
|
{
|
|
IsCheckIdle = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DPRINT_PNP("USBH_FdoPnP: IsCheckIdle - TRUE\n");
|
|
IsCheckIdle = TRUE;
|
|
USBH_HubSetD0(HubExtension);
|
|
}
|
|
|
|
switch (Minor)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_START_DEVICE\n");
|
|
IsCheckIdle = FALSE;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_FdoStartDevice(HubExtension, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_REMOVE_DEVICE\n");
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_REMOVE_DEVICE\n");
|
|
IsCheckIdle = FALSE;
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_FdoRemoveDevice(HubExtension, Irp);
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_CANCEL_REMOVE_DEVICE\n");
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_STOP_DEVICE\n");
|
|
IsCheckIdle = FALSE;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_FdoStopDevice(HubExtension, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_STOP_DEVICE\n");
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
DPRINT_PNP("FDO IRP_MN_CANCEL_STOP_DEVICE\n");
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_DEVICE_RELATIONS\n");
|
|
|
|
if (RelationsType != BusRelations)
|
|
{
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_HUB_BUSY;
|
|
|
|
IsCheckIdle = TRUE;
|
|
DPRINT_PNP("USBH_FdoPnP: IsCheckIdle - TRUE\n");
|
|
|
|
Status = USBH_FdoQueryBusRelations(HubExtension, Irp);
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HUB_BUSY;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_INTERFACE\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_CAPABILITIES\n");
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_QueryCapsComplete,
|
|
HubExtension,
|
|
TRUE,
|
|
FALSE,
|
|
FALSE);
|
|
|
|
Status = IoCallDriver(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCES:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_RESOURCES\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_DEVICE_TEXT\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
|
|
DPRINT_PNP("FDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_READ_CONFIG:
|
|
DPRINT_PNP("FDO IRP_MN_READ_CONFIG\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_WRITE_CONFIG:
|
|
DPRINT_PNP("FDO IRP_MN_WRITE_CONFIG\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_EJECT:
|
|
DPRINT_PNP("FDO IRP_MN_EJECT\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_SET_LOCK:
|
|
DPRINT_PNP("FDO IRP_MN_SET_LOCK\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_ID:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_ID\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_PNP_DEVICE_STATE\n");
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
|
|
{
|
|
Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
|
|
}
|
|
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_BUS_INFORMATION:
|
|
DPRINT_PNP("FDO IRP_MN_QUERY_BUS_INFORMATION\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
|
|
DPRINT_PNP("FDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
DPRINT_PNP("FDO IRP_MN_SURPRISE_REMOVAL\n");
|
|
USBH_FdoSurpriseRemoveDevice(HubExtension, Irp);
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
|
|
default:
|
|
DPRINT_PNP("FDO unknown IRP_MN_???\n");
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
KeReleaseSemaphore(&HubExtension->IdleSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (IsCheckIdle)
|
|
{
|
|
DPRINT_PNP("USBH_FdoPnP: call USBH_CheckIdleDeferred()\n");
|
|
USBH_CheckIdleDeferred(HubExtension);
|
|
}
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_STATE_CHANGING;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoPnP(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PIRP Irp,
|
|
IN UCHAR Minor,
|
|
OUT BOOLEAN * IsCompleteIrp)
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PPNP_BUS_INFORMATION BusInfo;
|
|
PDEVICE_CAPABILITIES DeviceCapabilities;
|
|
USHORT Size;
|
|
USHORT Version;
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
PDEVICE_RELATIONS DeviceRelation;
|
|
|
|
DPRINT_PNP("USBH_PdoPnP: PortExtension - %p, Irp - %p, Minor - %X\n",
|
|
PortExtension,
|
|
Irp,
|
|
Minor);
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
*IsCompleteIrp = TRUE;
|
|
|
|
switch (Minor)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_START_DEVICE\n");
|
|
return USBH_PdoStartDevice(PortExtension, Irp);
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_REMOVE_DEVICE\n");
|
|
return STATUS_SUCCESS;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_REMOVE_DEVICE\n");
|
|
return USBH_PdoRemoveDevice(PortExtension, PortExtension->HubExtension);
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_CANCEL_REMOVE_DEVICE\n");
|
|
return STATUS_SUCCESS;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_STOP_DEVICE\n");
|
|
return USBH_PdoStopDevice(PortExtension, Irp);
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_STOP_DEVICE\n");
|
|
return STATUS_SUCCESS;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
DPRINT_PNP("PDO IRP_MN_CANCEL_STOP_DEVICE\n");
|
|
return STATUS_SUCCESS;
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_DEVICE_RELATIONS\n");
|
|
|
|
if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
|
|
{
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
DeviceRelation = ExAllocatePoolWithTag(PagedPool,
|
|
sizeof(DEVICE_RELATIONS),
|
|
USB_HUB_TAG);
|
|
|
|
if (DeviceRelation)
|
|
{
|
|
RtlZeroMemory(DeviceRelation, sizeof(DEVICE_RELATIONS));
|
|
|
|
DeviceRelation->Count = 1;
|
|
DeviceRelation->Objects[0] = PortExtension->Common.SelfDevice;
|
|
|
|
ObReferenceObject(DeviceRelation->Objects[0]);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_INTERFACE\n");
|
|
|
|
*IsCompleteIrp = 0;
|
|
|
|
if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
|
|
&USB_BUS_INTERFACE_USBDI_GUID))
|
|
{
|
|
IoStack->Parameters.QueryInterface.InterfaceSpecificData = PortExtension->DeviceHandle;
|
|
}
|
|
|
|
HubExtension = PortExtension->HubExtension;
|
|
|
|
if (!HubExtension)
|
|
{
|
|
HubExtension = PortExtension->RootHubExtension;
|
|
}
|
|
|
|
Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_CAPABILITIES\n");
|
|
|
|
DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
Size = DeviceCapabilities->Size;
|
|
Version = DeviceCapabilities->Version;
|
|
|
|
RtlCopyMemory(DeviceCapabilities,
|
|
&PortExtension->Capabilities,
|
|
sizeof(DEVICE_CAPABILITIES));
|
|
|
|
DeviceCapabilities->Size = Size;
|
|
DeviceCapabilities->Version = Version;
|
|
|
|
/* All devices connected to a hub are removable */
|
|
DeviceCapabilities->Removable = 1;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCES:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_RESOURCES\n");
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_ENUMERATED;
|
|
|
|
/* FIXME HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Enum\USB\
|
|
Vid_????&Pid_????\????????????\Device Parameters\
|
|
if (ExtPropDescSemaphore)
|
|
*/
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_DEVICE_TEXT\n");
|
|
return USBH_PdoQueryDeviceText(PortExtension, Irp);
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
|
|
DPRINT_PNP("PDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_READ_CONFIG:
|
|
DPRINT_PNP("PDO IRP_MN_READ_CONFIG\n");
|
|
DbgBreakPoint();
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_WRITE_CONFIG:
|
|
DPRINT_PNP("PDO IRP_MN_WRITE_CONFIG\n");
|
|
DbgBreakPoint();
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_EJECT:
|
|
DPRINT_PNP("PDO IRP_MN_EJECT\n");
|
|
DbgBreakPoint();
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_SET_LOCK:
|
|
DPRINT_PNP("PDO IRP_MN_SET_LOCK\n");
|
|
DbgBreakPoint();
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_ID:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_ID\n");
|
|
return USBH_PdoQueryId(PortExtension, Irp);
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_PNP_DEVICE_STATE\n");
|
|
if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_INSUFFICIENT_PWR |
|
|
USBHUB_PDO_FLAG_OVERCURRENT_PORT |
|
|
USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
|
|
USBHUB_PDO_FLAG_INIT_PORT_FAILED))
|
|
{
|
|
Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_BUS_INFORMATION:
|
|
DPRINT_PNP("PDO IRP_MN_QUERY_BUS_INFORMATION\n");
|
|
|
|
BusInfo = ExAllocatePoolWithTag(PagedPool,
|
|
sizeof(PNP_BUS_INFORMATION),
|
|
USB_HUB_TAG);
|
|
|
|
if (!BusInfo)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(BusInfo, sizeof(PNP_BUS_INFORMATION));
|
|
|
|
RtlCopyMemory(&BusInfo->BusTypeGuid,
|
|
&GUID_BUS_TYPE_USB,
|
|
sizeof(BusInfo->BusTypeGuid));
|
|
|
|
BusInfo->LegacyBusType = PNPBus;
|
|
BusInfo->BusNumber = 0;
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
|
|
DPRINT_PNP("PDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
|
|
DbgBreakPoint();
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
DPRINT_PNP("PDO IRP_MN_SURPRISE_REMOVAL\n");
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)
|
|
{
|
|
Status = USBH_SymbolicLink(PortExtension, NULL, FALSE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
DPRINT_PNP("PDO unknown IRP_MN_???\n");
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|