add_subdirectory(usbd)
add_subdirectory(usbehci)
add_subdirectory(usbhub)
+#add_subdirectory(usbhub_new)
add_subdirectory(usbohci)
add_subdirectory(usbport)
add_subdirectory(usbstor)
--- /dev/null
+
+add_definitions(-DDEBUG_MODE)
+include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
+
+list(APPEND SOURCE
+ debug.c
+ ioctl.c
+ pnp.c
+ power.c
+ usbhub.c
+ usbhub.h)
+
+add_library(usbhub SHARED
+ ${SOURCE}
+ guid.c
+ usbhub.rc)
+
+target_link_libraries(usbhub ${PSEH_LIB})
+set_module_type(usbhub kernelmodedriver)
+add_importlibs(usbhub ntoskrnl hal wmilib usbd)
+add_pch(usbhub usbhub.h SOURCE)
+add_cd_file(TARGET usbhub DESTINATION reactos/system32/drivers NO_CAB FOR all)
--- /dev/null
+#ifndef DBG_UHUB_H__
+#define DBG_UHUB_H__
+
+#if DBG
+
+ #ifndef NDEBUG_USBHUB_IOCTL
+
+ #define DPRINT_IOCTL(fmt, ...) do { \
+ if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+ #else
+
+#if defined(_MSC_VER)
+ #define DPRINT_IOCTL __noop
+#else
+ #define DPRINT_IOCTL(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+ #endif
+
+ #ifndef NDEBUG_USBHUB_POWER
+
+ #define DPRINT_PWR(fmt, ...) do { \
+ if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+ #else
+
+#if defined(_MSC_VER)
+ #define DPRINT_PWR __noop
+#else
+ #define DPRINT_PWR(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+ #endif
+
+ #ifndef NDEBUG_USBHUB_PNP
+
+ #define DPRINT_PNP(fmt, ...) do { \
+ if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+ #else
+
+#if defined(_MSC_VER)
+ #define DPRINT_PNP __noop
+#else
+ #define DPRINT_PNP(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+ #endif
+
+ #ifndef NDEBUG_USBHUB_SCE
+
+ #define DPRINT_SCE(fmt, ...) do { \
+ if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+ #else
+
+#if defined(_MSC_VER)
+ #define DPRINT_SCE __noop
+#else
+ #define DPRINT_SCE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+ #endif
+
+ #ifndef NDEBUG_USBHUB_ENUM
+
+ #define DPRINT_ENUM(fmt, ...) do { \
+ if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \
+ DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+ } while (0)
+
+ #else
+
+#if defined(_MSC_VER)
+ #define DPRINT_ENUM __noop
+#else
+ #define DPRINT_ENUM(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+ #endif
+
+#else /* not DBG */
+
+#if defined(_MSC_VER)
+ #define DPRINT_IOCTL __noop
+ #define DPRINT_PWR __noop
+ #define DPRINT_PNP __noop
+ #define DPRINT_SCE __noop
+ #define DPRINT_ENUM __noop
+#else
+ #define DPRINT_IOCTL(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+ #define DPRINT_PWR(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+ #define DPRINT_PNP(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+ #define DPRINT_SCE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+ #define DPRINT_ENUM(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif /* _MSC_VER */
+
+#endif /* not DBG */
+
+#endif /* DBG_UHUB_H__ */
--- /dev/null
+#include "usbhub.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+VOID
+NTAPI
+USBHUB_DumpingDeviceDescriptor(IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
+{
+ if (!DeviceDescriptor)
+ {
+ return;
+ }
+
+ DPRINT("Dumping Device Descriptor - %p\n", DeviceDescriptor);
+ DPRINT("bLength - %x\n", DeviceDescriptor->bLength);
+ DPRINT("bDescriptorType - %x\n", DeviceDescriptor->bDescriptorType);
+ DPRINT("bcdUSB - %x\n", DeviceDescriptor->bcdUSB);
+ DPRINT("bDeviceClass - %x\n", DeviceDescriptor->bDeviceClass);
+ DPRINT("bDeviceSubClass - %x\n", DeviceDescriptor->bDeviceSubClass);
+ DPRINT("bDeviceProtocol - %x\n", DeviceDescriptor->bDeviceProtocol);
+ DPRINT("bMaxPacketSize0 - %x\n", DeviceDescriptor->bMaxPacketSize0);
+ DPRINT("idVendor - %x\n", DeviceDescriptor->idVendor);
+ DPRINT("idProduct - %x\n", DeviceDescriptor->idProduct);
+ DPRINT("bcdDevice - %x\n", DeviceDescriptor->bcdDevice);
+ DPRINT("iManufacturer - %x\n", DeviceDescriptor->iManufacturer);
+ DPRINT("iProduct - %x\n", DeviceDescriptor->iProduct);
+ DPRINT("iSerialNumber - %x\n", DeviceDescriptor->iSerialNumber);
+ DPRINT("bNumConfigurations - %x\n", DeviceDescriptor->bNumConfigurations);
+}
+
+VOID
+NTAPI
+USBHUB_DumpingConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor)
+{
+ PUSB_COMMON_DESCRIPTOR Descriptor;
+ PUSB_CONFIGURATION_DESCRIPTOR cDescriptor;
+ PUSB_INTERFACE_DESCRIPTOR iDescriptor;
+ PUSB_ENDPOINT_DESCRIPTOR eDescriptor;
+
+ if (!ConfigDescriptor)
+ {
+ return;
+ }
+
+ Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigDescriptor;
+
+ while ((ULONG_PTR)Descriptor <
+ ((ULONG_PTR)ConfigDescriptor + ConfigDescriptor->wTotalLength) &&
+ Descriptor->bLength)
+ {
+ if (Descriptor->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE)
+ {
+ cDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Descriptor;
+
+ DPRINT("Dumping cDescriptor - %p\n", cDescriptor);
+ DPRINT("bLength - %x\n", cDescriptor->bLength);
+ DPRINT("bDescriptorType - %x\n", cDescriptor->bDescriptorType);
+ DPRINT("wTotalLength - %x\n", cDescriptor->wTotalLength);
+ DPRINT("bNumInterfaces - %x\n", cDescriptor->bNumInterfaces);
+ DPRINT("bConfigurationValue - %x\n", cDescriptor->bConfigurationValue);
+ DPRINT("iConfiguration - %x\n", cDescriptor->iConfiguration);
+ DPRINT("bmAttributes - %x\n", cDescriptor->bmAttributes);
+ DPRINT("MaxPower - %x\n", cDescriptor->MaxPower);
+ }
+ else if (Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+ {
+ iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor;
+
+ DPRINT("Dumping iDescriptor - %p\n", iDescriptor);
+ DPRINT("bLength - %x\n", iDescriptor->bLength);
+ DPRINT("bDescriptorType - %x\n", iDescriptor->bDescriptorType);
+ DPRINT("bInterfaceNumber - %x\n", iDescriptor->bInterfaceNumber);
+ DPRINT("bAlternateSetting - %x\n", iDescriptor->bAlternateSetting);
+ DPRINT("bNumEndpoints - %x\n", iDescriptor->bNumEndpoints);
+ DPRINT("bInterfaceClass - %x\n", iDescriptor->bInterfaceClass);
+ DPRINT("bInterfaceSubClass - %x\n", iDescriptor->bInterfaceSubClass);
+ DPRINT("bInterfaceProtocol - %x\n", iDescriptor->bInterfaceProtocol);
+ DPRINT("iInterface - %x\n", iDescriptor->iInterface);
+ }
+ else if (Descriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
+ {
+ eDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Descriptor;
+
+ DPRINT("Dumping Descriptor - %p\n", eDescriptor);
+ DPRINT("bLength - %x\n", eDescriptor->bLength);
+ DPRINT("bDescriptorType - %x\n", eDescriptor->bDescriptorType);
+ DPRINT("bEndpointAddress - %x\n", eDescriptor->bEndpointAddress);
+ DPRINT("bmAttributes - %x\n", eDescriptor->bmAttributes);
+ DPRINT("wMaxPacketSize - %x\n", eDescriptor->wMaxPacketSize);
+ DPRINT("bInterval - %x\n", eDescriptor->bInterval);
+ }
+ else
+ {
+ DPRINT("bDescriptorType - %x\n", Descriptor->bDescriptorType);
+ }
+
+ Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor +
+ Descriptor->bLength);
+ }
+}
+
+VOID
+NTAPI
+USBHUB_DumpingIDs(IN PVOID Id)
+{
+ PWSTR Ptr;
+ ULONG Length;
+ ULONG TotalLength = 0;
+
+ Ptr = Id;
+ DPRINT("USBHUB_DumpingIDs:\n");
+
+ while (*Ptr)
+ {
+ DPRINT(" %S\n", Ptr);
+ Length = wcslen(Ptr) + 1;
+
+ Ptr += Length;
+ TotalLength += Length;
+ }
+
+ DPRINT("TotalLength: %hu\n", TotalLength);
+ DPRINT("\n");
+}
--- /dev/null
+/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
+
+#include <wdm.h>
+#include <initguid.h>
+#include <wdmguid.h>
+#include <usb.h>
+#include <usbiodef.h>
+#include <hubbusif.h>
+#include <usbbusif.h>
+
+/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */
--- /dev/null
+#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(USBHUB_PORT_STATUS));
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ PortStatus = IoStack->Parameters.Others.Argument1;
+
+ *PortStatus = 0;
+
+ if (PortExtension->Common.SelfDevice == PortData->DeviceObject)
+ {
+ if (PortData->PortStatus.UsbPortStatus.Usb20PortStatus.PortEnabledDisabled)
+ {
+ *PortStatus |= USBD_PORT_ENABLED;
+ }
+
+ if (PortData->PortStatus.UsbPortStatus.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;
+ ULONG LengthSkip;
+ PWCHAR Buffer;
+ ULONG BufferLength;
+ PWCHAR BufferEnd;
+ ULONG LengthReturned;
+ ULONG 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;
+}
--- /dev/null
+#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))
+ {
+ 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];
+
+ DPRINT_ENUM("USBH_FdoQueryBusRelations: Port - %x, ConnectStatus - %x\n",
+ Port,
+ PortData->PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
+ {
+ continue;
+ }
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortData->PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if (!NT_SUCCESS(Status))
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+ DeviceRelations->Count = 0;
+ goto EnumStart;
+ }
+
+ PdoDevice = PortData->DeviceObject;
+
+ if (PortData->DeviceObject)
+ {
+ PdoExtension = PdoDevice->DeviceExtension;
+
+ if (PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
+ {
+ PortData->PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
+ }
+ }
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
+ {
+ DPRINT1("USBH_FdoQueryBusRelations: DbgBreakPoint() \n");
+ DbgBreakPoint();
+ }
+
+ if (!PortData->PortStatus.UsbPortStatus.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(USBHUB_PORT_STATUS));
+
+ UsbPortStatus = PortData->PortStatus.UsbPortStatus;
+
+ 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.AsULONG = 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);
+ ULONG 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)
+ {
+ RtlStringCbPrintfExW(Buffer,
+ Remaining,
+ NULL,
+ &Remaining,
+ 0,
+ L"USB\\Vid_0000&Pid0000");
+ }
+ 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)
+ {
+ 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 - 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: BusQueryInstanceID - %S\n", Id);
+ }
+ else
+ {
+ USBHUB_DumpingIDs(Id);
+ }
+
+ break;
+
+ case BusQueryCompatibleIDs:
+ DPRINT("USBH_PdoQueryId: BusQueryCompatibleIDs\n");
+
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
+ {
+ 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 - 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: BusQueryInstanceID - %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;
+ ULONG NumSymbols;
+ ULONG 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(USBHUB_PORT_STATUS));
+
+ 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);
+
+ ASSERT(HubExtension);
+
+ if (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;
+
+ 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)
+ {
+ 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)
+ {
+ 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->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");
+
+ USBHUB_FlushAllTransfers(HubExtension);
+
+ IoDeleteDevice(PortDevice);
+ }
+ }
+
+ 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;
+
+ 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;
+}
--- /dev/null
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_POWER
+#include "dbg_uhub.h"
+
+VOID
+NTAPI
+USBH_CompletePowerIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN NTSTATUS NtStatus)
+{
+ DPRINT("USBH_CompletePowerIrp: HubExtension - %p, Irp - %p, NtStatus - %lX\n",
+ HubExtension,
+ Irp,
+ NtStatus);
+
+ Irp->IoStatus.Status = NtStatus;
+
+ PoStartNextPowerIrp(Irp);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+NTAPI
+USBH_HubCancelWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ DPRINT("USBH_HubCancelWakeIrp: HubExtension - %p, Irp - %p\n",
+ HubExtension,
+ Irp);
+
+ IoCancelIrp(Irp);
+
+ if (InterlockedExchange((PLONG)&HubExtension->FdoWaitWakeLock, 1))
+ {
+ PoStartNextPowerIrp(Irp);
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+}
+
+VOID
+NTAPI
+USBH_HubESDRecoverySetD3Completion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ DPRINT("USBH_HubESDRecoverySetD3Completion ... \n");
+
+ KeSetEvent((PRKEVENT)Context,
+ EVENT_INCREMENT,
+ FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBH_HubSetD0(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSBHUB_FDO_EXTENSION RootHubDevExt;
+ NTSTATUS Status;
+ KEVENT Event;
+ POWER_STATE PowerState;
+
+ DPRINT("USBH_HubSetD0: HubExtension - %p\n", HubExtension);
+
+ RootHubDevExt = USBH_GetRootHubExtension(HubExtension);
+
+ if (RootHubDevExt->SystemPowerState.SystemState != PowerSystemWorking)
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ return Status;
+ }
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+ {
+ DPRINT("USBH_HubSetD0: HubFlags - %lX\n", HubExtension->HubFlags);
+
+ KeWaitForSingleObject(&HubExtension->IdleEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ PowerState.DeviceState = PowerDeviceD0;
+
+ Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ PowerState,
+ USBH_HubESDRecoverySetD3Completion,
+ &Event,
+ NULL);
+
+ if (Status == STATUS_PENDING)
+ {
+ Status = KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ while (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAKEUP_START)
+ {
+ USBH_Wait(10);
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_IdleCancelPowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ PUSBHUB_IDLE_PORT_CANCEL_CONTEXT WorkItemIdlePower;
+ PIRP Irp;
+
+ DPRINT("USBH_IdleCancelPowerHubWorker: ... \n");
+
+ WorkItemIdlePower = Context;
+
+ if (HubExtension &&
+ HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ USBH_HubSetD0(HubExtension);
+ }
+
+ Irp = WorkItemIdlePower->Irp;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+NTAPI
+USBH_HubQueuePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PLIST_ENTRY ListIrps)
+{
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ USHORT NumPorts;
+ USHORT Port;
+ PIRP WakeIrp;
+ KIRQL OldIrql;
+
+ DPRINT("USBH_HubQueuePortWakeIrps ... \n");
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ InitializeListHead(ListIrps);
+
+ IoAcquireCancelSpinLock(&OldIrql);
+
+ for (Port = 0; Port < NumPorts; ++Port)
+ {
+ PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+ if (PortDevice)
+ {
+ PortExtension = PortDevice->DeviceExtension;
+
+ WakeIrp = PortExtension->PdoWaitWakeIrp;
+ PortExtension->PdoWaitWakeIrp = NULL;
+
+ if (WakeIrp)
+ {
+ DPRINT1("USBH_HubQueuePortWakeIrps: UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+ }
+ }
+
+ IoReleaseCancelSpinLock(OldIrql);
+}
+
+VOID
+NTAPI
+USBH_HubCompleteQueuedPortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PLIST_ENTRY ListIrps,
+ IN NTSTATUS NtStatus)
+{
+ DPRINT("USBH_HubCompleteQueuedPortWakeIrps ... \n");
+
+ while (!IsListEmpty(ListIrps))
+ {
+ DPRINT1("USBH_HubCompleteQueuedPortWakeIrps: UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+}
+
+VOID
+NTAPI
+USBH_HubCompletePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN NTSTATUS NtStatus)
+{
+ LIST_ENTRY ListIrps;
+
+ DPRINT("USBH_HubCompletePortWakeIrps: NtStatus - %x\n", NtStatus);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ USBH_HubQueuePortWakeIrps(HubExtension, &ListIrps);
+
+ USBH_HubCompleteQueuedPortWakeIrps(HubExtension,
+ &ListIrps,
+ NtStatus);
+ }
+}
+
+VOID
+NTAPI
+USBH_FdoPoRequestD0Completion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+
+ DPRINT("USBH_FdoPoRequestD0Completion ... \n");
+
+ HubExtension = Context;
+
+ USBH_HubCompletePortWakeIrps(HubExtension, STATUS_SUCCESS);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAKEUP_START;
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+}
+
+VOID
+NTAPI
+USBH_CompletePortWakeIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ DPRINT1("USBH_CompletePortWakeIrpsWorker: UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoWWIrpIoCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ NTSTATUS Status;
+ KIRQL OldIrql;
+ POWER_STATE PowerState;
+ PIRP WakeIrp;
+
+ DPRINT("USBH_FdoWWIrpIoCompletion: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+
+ HubExtension = Context;
+
+ Status = Irp->IoStatus.Status;
+
+ IoAcquireCancelSpinLock(&OldIrql);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+ WakeIrp = InterlockedExchangePointer((PVOID *)&HubExtension->PendingWakeIrp,
+ NULL);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ IoReleaseCancelSpinLock(OldIrql);
+
+ DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_FdoWWIrpIoCompletion: DbgBreakPoint() \n");
+ DbgBreakPoint();
+ }
+ else
+ {
+ PowerState.DeviceState = PowerDeviceD0;
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAKEUP_START;
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ Status = STATUS_SUCCESS;
+
+ PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ PowerState,
+ USBH_FdoPoRequestD0Completion,
+ (PVOID)HubExtension,
+ NULL);
+ }
+
+ if (!WakeIrp)
+ {
+ if (!InterlockedExchange(&HubExtension->FdoWaitWakeLock, 1))
+ {
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ }
+
+ DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PoStartNextPowerIrp(Irp);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PIO_STACK_LOCATION IoStack;
+ DEVICE_POWER_STATE OldDeviceState;
+ NTSTATUS Status;
+ POWER_STATE PowerState;
+
+ DPRINT("USBH_PowerIrpCompletion: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+
+ HubExtension = Context;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ PowerState = IoStack->Parameters.Power.State;
+
+ Status = Irp->IoStatus.Status;
+ DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (PowerState.DeviceState == PowerDeviceD0)
+ {
+ PoStartNextPowerIrp(Irp);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
+ }
+ }
+ else if (PowerState.DeviceState == PowerDeviceD0)
+ {
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
+
+ OldDeviceState = HubExtension->CurrentPowerState.DeviceState;
+ HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+ DPRINT("USBH_PowerIrpCompletion: OldDeviceState - %x\n", OldDeviceState);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_HIBERNATE_STATE)
+ {
+ DPRINT1("USBH_PowerIrpCompletion: USBHUB_FDO_FLAG_HIBERNATE_STATE. FIXME\n");
+ DbgBreakPoint();
+ }
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HIBERNATE_STATE;
+
+ if (OldDeviceState == PowerDeviceD3)
+ {
+ DPRINT1("USBH_PowerIrpCompletion: PowerDeviceD3. FIXME\n");
+ DbgBreakPoint();
+ }
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED) &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION)
+ {
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+ }
+
+ DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PoStartNextPowerIrp(Irp);
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoDeferPoRequestCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ PUSBHUB_FDO_EXTENSION Extension;
+ PUSBHUB_FDO_EXTENSION HubExtension = NULL;
+ PIRP PowerIrp;
+ PIO_STACK_LOCATION IoStack;
+
+ DPRINT("USBH_FdoDeferPoRequestCompletion ... \n");
+
+ Extension = Context;
+
+ PowerIrp = Extension->PowerIrp;
+
+ if (Extension->Common.ExtensionType == USBH_EXTENSION_TYPE_HUB)
+ {
+ HubExtension = Context;
+ }
+
+ IoStack = IoGetCurrentIrpStackLocation(PowerIrp);
+
+ if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking &&
+ HubExtension && HubExtension->LowerPDO == HubExtension->RootHubPdo)
+ {
+ HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
+ USBH_CheckIdleDeferred(HubExtension);
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(PowerIrp);
+ PoStartNextPowerIrp(PowerIrp);
+ PoCallDriver(Extension->LowerDevice, PowerIrp);
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoPower(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor)
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ POWER_STATE PowerState;
+ POWER_STATE DevicePwrState;
+ BOOLEAN IsAllPortsD3;
+ PUSBHUB_PORT_DATA PortData;
+ PDEVICE_OBJECT PdoDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ ULONG Port;
+
+ DPRINT_PWR("USBH_FdoPower: HubExtension - %p, Irp - %p, Minor - %X\n",
+ HubExtension,
+ Irp,
+ Minor);
+
+ switch (Minor)
+ {
+ case IRP_MN_WAIT_WAKE:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_WAIT_WAKE\n");
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_FdoWWIrpIoCompletion,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ PoStartNextPowerIrp(Irp);
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return STATUS_PENDING;
+
+ case IRP_MN_POWER_SEQUENCE:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_POWER_SEQUENCE\n");
+ break;
+
+ case IRP_MN_SET_POWER:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER\n");
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER/DevicePowerState\n");
+ PowerState = IoStack->Parameters.Power.State;
+
+ if (IoStack->Parameters.Power.Type == DevicePowerState)
+ {
+ DPRINT_PWR("USBH_FdoPower: PowerState - %x\n",
+ PowerState.DeviceState);
+
+ if (HubExtension->CurrentPowerState.DeviceState == PowerState.DeviceState)
+ {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ PoStartNextPowerIrp(Irp);
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return STATUS_PENDING;
+ }
+
+ switch (PowerState.DeviceState)
+ {
+ case PowerDeviceD0:
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_SET_D0_STATE))
+ {
+ HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_SET_D0_STATE;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_PowerIrpCompletion,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+ }
+ else
+ {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+ }
+
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+ return STATUS_PENDING;
+
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3:
+ if (HubExtension->ResetRequestCount)
+ {
+ IoCancelIrp(HubExtension->ResetPortIrp);
+
+ KeWaitForSingleObject(&HubExtension->ResetEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ HubExtension->HubFlags |= (USBHUB_FDO_FLAG_NOT_D0_STATE |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+ IoCancelIrp(HubExtension->SCEIrp);
+
+ KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ HubExtension->CurrentPowerState.DeviceState = PowerState.DeviceState;
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE &&
+ USBH_CheckIdleAbort(HubExtension, TRUE, TRUE) == TRUE)
+ {
+ HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+ HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+
+ PoStartNextPowerIrp(Irp);
+
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+ KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_PowerIrpCompletion,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ PoStartNextPowerIrp(Irp);
+ IoMarkIrpPending(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE)
+ {
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+ KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+ }
+
+ return STATUS_PENDING;
+
+ default:
+ DPRINT1("USBH_FdoPower: Unsupported PowerState.DeviceState\n");
+ DbgBreakPoint();
+ break;
+ }
+ }
+ else
+ {
+ if (PowerState.SystemState != PowerSystemWorking)
+ {
+ USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState =
+ PowerState.SystemState;
+ }
+
+ if (PowerState.SystemState == PowerSystemHibernate)
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_HIBERNATE_STATE;
+ }
+
+ PortData = HubExtension->PortData;
+
+ IsAllPortsD3 = TRUE;
+
+ if (PortData && HubExtension->HubDescriptor)
+ {
+ for (Port = 0;
+ Port < HubExtension->HubDescriptor->bNumberOfPorts;
+ Port++)
+ {
+ PdoDevice = PortData[Port].DeviceObject;
+
+ if (PdoDevice)
+ {
+ PortExtension = PdoDevice->DeviceExtension;
+
+ if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD3)
+ {
+ IsAllPortsD3 = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (PowerState.SystemState == PowerSystemWorking)
+ {
+ DevicePwrState.DeviceState = PowerDeviceD0;
+ }
+ else if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP ||
+ !IsAllPortsD3)
+ {
+ DevicePwrState.DeviceState = HubExtension->DeviceState[PowerState.SystemState];
+
+ if (DevicePwrState.DeviceState == PowerDeviceUnspecified)
+ {
+ goto Exit;
+ }
+ }
+ else
+ {
+ DevicePwrState.DeviceState = PowerDeviceD3;
+ }
+
+ if (DevicePwrState.DeviceState != HubExtension->CurrentPowerState.DeviceState &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ HubExtension->PowerIrp = Irp;
+
+ IoMarkIrpPending(Irp);
+
+ if (PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ DevicePwrState,
+ USBH_FdoDeferPoRequestCompletion,
+ (PVOID)HubExtension,
+ NULL) == STATUS_PENDING)
+ {
+ return STATUS_PENDING;
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+ PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return STATUS_PENDING;
+ }
+
+ Exit:
+
+ HubExtension->SystemPowerState.SystemState = PowerState.SystemState;
+
+ if (PowerState.SystemState == PowerSystemWorking)
+ {
+ USBH_CheckIdleDeferred(HubExtension);
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+
+ return PoCallDriver(HubExtension->LowerDevice, Irp);
+ }
+
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ DPRINT_PWR("USBH_FdoPower: IRP_MN_QUERY_POWER\n");
+ break;
+
+ default:
+ DPRINT1("USBH_FdoPower: unknown IRP_MN_POWER!\n");
+ break;
+ }
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ PoStartNextPowerIrp(Irp);
+ Status = PoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoPower(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor)
+{
+ NTSTATUS Status = Irp->IoStatus.Status;
+
+ DPRINT_PWR("USBH_FdoPower: PortExtension - %p, Irp - %p, Minor - %X\n",
+ PortExtension,
+ Irp,
+ Minor);
+
+ switch (Minor)
+ {
+ case IRP_MN_WAIT_WAKE:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_WAIT_WAKE\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ case IRP_MN_POWER_SEQUENCE:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_POWER_SEQUENCE\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ case IRP_MN_SET_POWER:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_SET_POWER\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ DPRINT_PWR("USBHUB_PdoPower: IRP_MN_QUERY_POWER\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+
+ default:
+ DPRINT1("USBHUB_PdoPower: unknown IRP_MN_POWER!\n");
+ PoStartNextPowerIrp(Irp);
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
--- /dev/null
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_SCE
+#define NDEBUG_USBHUB_PNP
+#include "dbg_uhub.h"
+
+#include <ntddstor.h>
+
+PWSTR GenericUSBDeviceString = NULL;
+
+NTSTATUS
+NTAPI
+USBH_Wait(IN ULONG Milliseconds)
+{
+ LARGE_INTEGER Interval;
+
+ DPRINT("USBH_Wait: Milliseconds - %x\n", Milliseconds);
+ Interval.QuadPart = -10000 * Milliseconds + (KeQueryTimeIncrement() - 1);
+ return KeDelayExecutionThread(KernelMode, FALSE, &Interval);
+}
+
+NTSTATUS
+NTAPI
+USBH_GetConfigValue(IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DPRINT("USBHUB_GetConfigValue: ... \n");
+
+ if (ValueType == REG_BINARY)
+ {
+ *(PUCHAR)EntryContext = *(PUCHAR)ValueData;
+ }
+ else if (ValueType == REG_DWORD)
+ {
+ *(PULONG)EntryContext = *(PULONG)ValueData;
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_CompleteIrp(IN PIRP Irp,
+ IN NTSTATUS CompleteStatus)
+{
+ if (CompleteStatus != STATUS_SUCCESS)
+ {
+ DPRINT1("USBH_CompleteIrp: Irp - %p, CompleteStatus - %X\n",
+ Irp,
+ CompleteStatus);
+ }
+
+ Irp->IoStatus.Status = CompleteStatus;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+NTSTATUS
+NTAPI
+USBH_PassIrp(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT_PNP("USBH_PassIrp: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncIrpComplete(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
+ KIRQL OldIrql;
+ BOOLEAN TimerCancelled;
+
+ DPRINT("USBH_SyncIrpComplete: ... \n");
+
+ HubTimeoutContext = Context;
+
+ KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
+ HubTimeoutContext->IsNormalCompleted = TRUE;
+ TimerCancelled = KeCancelTimer(&HubTimeoutContext->UrbTimeoutTimer);
+ KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
+
+ if (TimerCancelled)
+ {
+ KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+NTAPI
+IsBitSet(IN PUCHAR BitMapAddress,
+ IN USHORT Bit)
+{
+ BOOLEAN IsSet;
+
+ IsSet = (BitMapAddress[Bit / 8] & (1 << (Bit & 7))) != 0;
+ DPRINT("IsBitSet: Bit - %lX, IsSet - %x\n", Bit, IsSet);
+ return IsSet;
+}
+
+PUSBHUB_PORT_PDO_EXTENSION
+NTAPI
+PdoExt(IN PDEVICE_OBJECT DeviceObject)
+{
+ PVOID PdoExtension;
+
+ DPRINT("PdoExt: DeviceObject - %p\n", DeviceObject);
+
+ if (DeviceObject)
+ {
+ PdoExtension = DeviceObject->DeviceExtension;
+ }
+ else
+ {
+ PdoExtension = NULL;
+ }
+
+ return (PUSBHUB_PORT_PDO_EXTENSION)PdoExtension;
+}
+
+NTSTATUS
+NTAPI
+USBH_WriteFailReasonID(IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG FailReason)
+{
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FailReasonID");
+
+ DPRINT("USBH_WriteFailReason: ID - %x\n", FailReason);
+
+ Status = IoOpenDeviceRegistryKey(DeviceObject,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ &KeyHandle);
+
+ if (NT_SUCCESS(Status))
+ {
+ ZwSetValueKey(KeyHandle,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &FailReason,
+ sizeof(FailReason));
+
+ ZwClose(KeyHandle);
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_UrbTimeoutDPC(IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
+{
+ PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
+ KIRQL OldIrql;
+ BOOL IsCompleted;
+
+ DPRINT("USBH_TimeoutDPC ... \n");
+
+ HubTimeoutContext = DeferredContext;
+
+ KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
+ IsCompleted = HubTimeoutContext->IsNormalCompleted;
+ KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
+
+ if (!IsCompleted)
+ {
+ IoCancelIrp(HubTimeoutContext->Irp);
+ }
+
+ KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
+ EVENT_INCREMENT,
+ FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBH_SetPdoRegistryParameter(IN PDEVICE_OBJECT DeviceObject,
+ IN PCWSTR ValueName,
+ IN PVOID Data,
+ IN ULONG DataSize,
+ IN ULONG Type,
+ IN ULONG DevInstKeyType)
+{
+ NTSTATUS Status;
+ UNICODE_STRING ValueNameString;
+ HANDLE KeyHandle;
+
+ DPRINT("USBH_SetPdoRegistryParameter ... \n");
+
+ RtlInitUnicodeString(&ValueNameString, ValueName);
+
+ Status = IoOpenDeviceRegistryKey(DeviceObject,
+ DevInstKeyType,
+ STANDARD_RIGHTS_ALL,
+ &KeyHandle);
+
+ if (NT_SUCCESS(Status))
+ {
+ ZwSetValueKey(KeyHandle,
+ &ValueNameString,
+ 0,
+ Type,
+ Data,
+ DataSize);
+
+ ZwClose(KeyHandle);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncSubmitUrb(IN PDEVICE_OBJECT DeviceObject,
+ IN PURB Urb)
+{
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
+ BOOLEAN IsWaitTimeout = FALSE;
+ LARGE_INTEGER DueTime;
+ NTSTATUS Status;
+
+ DPRINT("USBH_SyncSubmitUrb: ... \n");
+
+ Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
+ DeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+
+ if (!Irp)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+ IoStack->Parameters.Others.Argument1 = Urb;
+
+ HubTimeoutContext = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(USBHUB_URB_TIMEOUT_CONTEXT),
+ USB_HUB_TAG);
+
+ if (HubTimeoutContext)
+ {
+ RtlZeroMemory(HubTimeoutContext, sizeof(USBHUB_URB_TIMEOUT_CONTEXT));
+
+ HubTimeoutContext->Irp = Irp;
+ HubTimeoutContext->IsNormalCompleted = FALSE;
+
+ KeInitializeEvent(&HubTimeoutContext->UrbTimeoutEvent,
+ NotificationEvent,
+ FALSE);
+
+ KeInitializeSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock);
+ KeInitializeTimer(&HubTimeoutContext->UrbTimeoutTimer);
+
+ KeInitializeDpc(&HubTimeoutContext->UrbTimeoutDPC,
+ USBH_UrbTimeoutDPC,
+ HubTimeoutContext);
+
+ DueTime.QuadPart = -5000 * 10000; // Timeout 5 sec.
+
+ KeSetTimer(&HubTimeoutContext->UrbTimeoutTimer,
+ DueTime,
+ &HubTimeoutContext->UrbTimeoutDPC);
+
+ IoSetCompletionRoutine(Irp,
+ USBH_SyncIrpComplete,
+ HubTimeoutContext,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ IsWaitTimeout = TRUE;
+ }
+
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ else
+ {
+ IoStatusBlock.Status = Status;
+ }
+
+ if (IsWaitTimeout)
+ {
+ KeWaitForSingleObject(&HubTimeoutContext->UrbTimeoutEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ExFreePoolWithTag(HubTimeoutContext, USB_HUB_TAG);
+ }
+
+ return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoSyncSubmitUrb(IN PDEVICE_OBJECT FdoDevice,
+ IN PURB Urb)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+
+ DPRINT("USBH_FdoSyncSubmitUrb: FdoDevice - %p, Urb - %p\n",
+ FdoDevice,
+ Urb);
+
+ HubExtension = FdoDevice->DeviceExtension;
+ return USBH_SyncSubmitUrb(HubExtension->LowerDevice, Urb);
+}
+
+NTSTATUS
+NTAPI
+USBH_Transact(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID TransferBuffer,
+ IN ULONG BufferLen,
+ IN BOOLEAN IsDeviceToHost,
+ IN USHORT Function,
+ IN BM_REQUEST_TYPE RequestType,
+ IN UCHAR Request,
+ IN USHORT RequestValue,
+ IN USHORT RequestIndex)
+{
+ struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb;
+ ULONG TransferFlags;
+ PVOID Buffer = NULL;
+ ULONG Length;
+ NTSTATUS Status;
+
+ DPRINT("USBH_Transact: ... \n");
+
+ if (BufferLen)
+ {
+ Length = ALIGN_DOWN_BY(BufferLen + sizeof(ULONG), sizeof(ULONG));
+
+ Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
+
+ if (!Buffer)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Buffer, Length);
+ }
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+ USB_HUB_TAG);
+
+ if (!Urb)
+ {
+ if (Buffer)
+ {
+ ExFreePoolWithTag(Buffer, USB_HUB_TAG);
+ }
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+ if (IsDeviceToHost)
+ {
+ if (BufferLen)
+ {
+ RtlZeroMemory(TransferBuffer, BufferLen);
+ }
+
+ TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
+ }
+ else
+ {
+ if (BufferLen)
+ {
+ RtlCopyMemory(Buffer, TransferBuffer, BufferLen);
+ }
+
+ TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
+ }
+
+ Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+ Urb->Hdr.Function = Function;
+ Urb->Hdr.UsbdDeviceHandle = NULL;
+
+ Urb->TransferFlags = TransferFlags;
+ Urb->TransferBuffer = BufferLen != 0 ? Buffer : NULL;
+ Urb->TransferBufferLength = BufferLen;
+ Urb->TransferBufferMDL = NULL;
+ Urb->UrbLink = NULL;
+
+ Urb->RequestTypeReservedBits = RequestType.B;
+ Urb->Request = Request;
+ Urb->Value = RequestValue;
+ Urb->Index = RequestIndex;
+
+ Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, (PURB)Urb);
+
+ if (IsDeviceToHost && BufferLen)
+ {
+ RtlCopyMemory(TransferBuffer, Buffer, BufferLen);
+ }
+
+ if (Buffer)
+ {
+ ExFreePoolWithTag(Buffer, USB_HUB_TAG);
+ }
+
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncResetPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port)
+{
+ USBHUB_PORT_STATUS PortStatus;
+ KEVENT Event;
+ LARGE_INTEGER Timeout;
+ ULONG ResetRetry = 0;
+ NTSTATUS Status;
+
+ DPRINT("USBH_SyncResetPort: Port - %x\n", Port);
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->HubPortSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if (NT_SUCCESS(Status) &&
+ (PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 0))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ goto Exit;
+ }
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+ while (TRUE)
+ {
+ BM_REQUEST_TYPE RequestType;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+ &Event);
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_DEVICE;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+ Status = USBH_Transact(HubExtension,
+ NULL,
+ 0,
+ BMREQUEST_HOST_TO_DEVICE,
+ URB_FUNCTION_CLASS_OTHER,
+ RequestType,
+ USB_REQUEST_SET_FEATURE,
+ USBHUB_FEATURE_PORT_RESET,
+ Port);
+
+ Timeout.QuadPart = -5000 * 10000;
+
+ if (!NT_SUCCESS(Status))
+ {
+ InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+ NULL);
+
+ USBH_Wait(10);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+ goto Exit;
+ }
+
+ Status = KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ &Timeout);
+
+ if (Status != STATUS_TIMEOUT)
+ {
+ break;
+ }
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if (!NT_SUCCESS(Status) ||
+ (PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 0) ||
+ ResetRetry >= USBHUB_RESET_PORT_MAX_RETRY)
+ {
+ InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+ NULL);
+
+ USBH_Wait(10);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+ Status = STATUS_DEVICE_DATA_ERROR;
+ goto Exit;
+ }
+
+ ResetRetry++;
+ }
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if ((PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 0) &&
+ NT_SUCCESS(Status) &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
+ {
+ Status = STATUS_DEVICE_DATA_ERROR;
+ }
+
+ USBH_Wait(10);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+Exit:
+
+ KeReleaseSemaphore(&HubExtension->HubPortSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetDeviceType(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE DeviceHandle,
+ OUT USB_DEVICE_TYPE * OutDeviceType)
+{
+ PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
+ PUSB_DEVICE_INFORMATION_0 DeviceInfo;
+ SIZE_T DeviceInformationBufferLength;
+ USB_DEVICE_TYPE DeviceType = Usb11Device;
+ ULONG dummy;
+ NTSTATUS Status;
+
+ DPRINT("USBH_GetDeviceType: ... \n");
+
+ QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
+
+ if (!QueryDeviceInformation)
+ {
+ DPRINT1("USBH_GetDeviceType: no QueryDeviceInformation()\n");
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ DeviceInformationBufferLength = sizeof(USB_DEVICE_INFORMATION_0);
+
+ while (TRUE)
+ {
+ DeviceInfo = ExAllocatePoolWithTag(PagedPool,
+ DeviceInformationBufferLength,
+ USB_HUB_TAG);
+
+ if (!DeviceInfo)
+ {
+ DPRINT1("USBH_GetDeviceType: ExAllocatePoolWithTag() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ RtlZeroMemory(DeviceInfo, DeviceInformationBufferLength);
+
+ DeviceInfo->InformationLevel = 0;
+
+ Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
+ DeviceHandle,
+ DeviceInfo,
+ DeviceInformationBufferLength,
+ &dummy);
+
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ if (NT_SUCCESS(Status))
+ {
+ DeviceType = DeviceInfo->DeviceType;
+ }
+
+ ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+ break;
+ }
+
+ DeviceInformationBufferLength = DeviceInfo->ActualLength;
+ ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+ }
+
+ if (OutDeviceType)
+ {
+ *OutDeviceType = DeviceType;
+ DPRINT("USBH_GetDeviceType: DeviceType - %x\n", DeviceType);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBHUB_GetExtendedHubInfo(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer)
+{
+ PUSB_BUSIFFN_GET_EXTENDED_HUB_INFO GetExtendedHubInformation;
+ ULONG dummy = 0;
+
+ DPRINT("USBHUB_GetExtendedHubInfo: ... \n");
+
+ GetExtendedHubInformation = HubExtension->BusInterface.GetExtendedHubInformation;
+
+ return GetExtendedHubInformation(HubExtension->BusInterface.BusContext,
+ HubExtension->LowerPDO,
+ HubInfoBuffer,
+ sizeof(USB_EXTHUB_INFORMATION_0),
+ &dummy);
+}
+
+PUSBHUB_FDO_EXTENSION
+NTAPI
+USBH_GetRootHubExtension(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PDEVICE_OBJECT Device;
+ PUSBHUB_FDO_EXTENSION RootHubExtension;
+
+ DPRINT("USBH_GetRootHubExtension: HubExtension - %p\n", HubExtension);
+
+ RootHubExtension = HubExtension;
+
+ if (HubExtension->LowerPDO != HubExtension->RootHubPdo)
+ {
+ Device = HubExtension->RootHubPdo;
+
+ do
+ {
+ Device = Device->AttachedDevice;
+ }
+ while (Device->DriverObject != HubExtension->Common.SelfDevice->DriverObject);
+
+ RootHubExtension = Device->DeviceExtension;
+ }
+
+ DPRINT("USBH_GetRootHubExtension: RootHubExtension - %p\n", RootHubExtension);
+
+ return RootHubExtension;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetRootHubPdo(IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PDEVICE_OBJECT * OutPdo1,
+ IN OUT PDEVICE_OBJECT * OutPdo2)
+{
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+
+ DPRINT("USBH_SyncGetRootHubPdo: ... \n");
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
+ DeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+
+ if (!Irp)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+ IoStack->Parameters.Others.Argument1 = OutPdo1;
+ IoStack->Parameters.Others.Argument2 = OutPdo2;
+
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ else
+ {
+ IoStatusBlock.Status = Status;
+ }
+
+ return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetHubCount(IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PULONG OutHubCount)
+{
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+
+ DPRINT("USBH_SyncGetHubCount: *OutHubCount - %x\n", *OutHubCount);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_HUB_COUNT,
+ DeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+
+ if (!Irp)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+ IoStack->Parameters.Others.Argument1 = OutHubCount;
+
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ else
+ {
+ IoStatusBlock.Status = Status;
+ }
+
+ return IoStatusBlock.Status;
+}
+
+PUSB_DEVICE_HANDLE
+NTAPI
+USBH_SyncGetDeviceHandle(IN PDEVICE_OBJECT DeviceObject)
+{
+ PIRP Irp;
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PUSB_DEVICE_HANDLE DeviceHandle = NULL;
+ PIO_STACK_LOCATION IoStack;
+
+ DPRINT("USBH_SyncGetDeviceHandle: ... \n");
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
+ DeviceObject,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+
+ if (!Irp)
+ {
+ DPRINT1("USBH_SyncGetDeviceHandle: Irp - NULL!\n");
+ return NULL;
+ }
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+ IoStack->Parameters.Others.Argument1 = &DeviceHandle;
+
+ if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ return DeviceHandle;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor)
+{
+ struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
+ NTSTATUS Status;
+
+ DPRINT("USBH_GetDeviceDescriptor: ... \n");
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_HUB_TAG);
+
+ if (!Urb)
+ {
+ DPRINT1("USBH_SyncGetDeviceHandle: Urb - NULL!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ 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->TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
+ Urb->TransferBuffer = HubDeviceDescriptor;
+ Urb->DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
+
+ Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
+
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetDeviceConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
+ IN ULONG NumberOfBytes,
+ IN PULONG OutLength)
+{
+ PCOMMON_DEVICE_EXTENSION DeviceExtension;
+ struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
+ NTSTATUS Status;
+
+ DPRINT("USBH_SyncGetDeviceConfigurationDescriptor: ... \n");
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+
+ if (OutLength)
+ {
+ *OutLength = 0;
+ }
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_HUB_TAG);
+
+ if (!Urb)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ 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->TransferBufferLength = NumberOfBytes;
+ Urb->TransferBuffer = ConfigDescriptor;
+ Urb->DescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
+
+ if (DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_HUB ||
+ DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_PARENT)
+ {
+ Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
+ }
+ else
+ {
+ Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
+ }
+
+ if (OutLength)
+ {
+ *OutLength = Urb->TransferBufferLength;
+ }
+
+ if (Urb)
+ {
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_CONFIGURATION_DESCRIPTOR * OutDescriptor)
+{
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+ ULONG ReturnedLen;
+ SIZE_T DescriptorLen;
+ NTSTATUS Status;
+
+ DPRINT("USBH_GetConfigurationDescriptor: ... \n");
+
+ DescriptorLen = MAXUCHAR;
+
+ while (TRUE)
+ {
+ ConfigDescriptor = ExAllocatePoolWithTag(NonPagedPool,
+ DescriptorLen,
+ USB_HUB_TAG);
+
+ if (!ConfigDescriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ Status = USBH_SyncGetDeviceConfigurationDescriptor(DeviceObject,
+ ConfigDescriptor,
+ DescriptorLen,
+ &ReturnedLen);
+
+ if (ReturnedLen < sizeof(USB_CONFIGURATION_DESCRIPTOR))
+ {
+ Status = STATUS_DEVICE_DATA_ERROR;
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ *OutDescriptor = ConfigDescriptor;
+
+ if (ConfigDescriptor->wTotalLength <= DescriptorLen)
+ {
+ break;
+ }
+
+ DescriptorLen = ConfigDescriptor->wTotalLength;
+
+ ExFreePool(ConfigDescriptor);
+ *OutDescriptor = NULL;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ if (ReturnedLen < ConfigDescriptor->wTotalLength)
+ {
+ Status = STATUS_DEVICE_DATA_ERROR;
+ }
+ }
+ else
+ {
+ if (ConfigDescriptor)
+ {
+ ExFreePool(ConfigDescriptor);
+ }
+
+ *OutDescriptor = NULL;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetHubDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSB_EXTHUB_INFORMATION_0 ExtendedHubInfo;
+ ULONG NumberPorts;
+ PUSBHUB_PORT_DATA PortData;
+ USHORT RequestValue;
+ ULONG NumberOfBytes;
+ NTSTATUS Status;
+ PUSB_HUB_DESCRIPTOR HubDescriptor = NULL;
+ ULONG ix;
+ ULONG Retry;
+
+ DPRINT("USBH_SyncGetHubDescriptor: ... \n");
+
+ ExtendedHubInfo = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(USB_EXTHUB_INFORMATION_0),
+ USB_HUB_TAG);
+
+ if (!ExtendedHubInfo)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ErrorExit;
+ }
+
+ RtlZeroMemory(ExtendedHubInfo, sizeof(USB_EXTHUB_INFORMATION_0));
+
+ Status = USBHUB_GetExtendedHubInfo(HubExtension, ExtendedHubInfo);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
+ ExtendedHubInfo = NULL;
+ }
+
+ NumberOfBytes = sizeof(USB_HUB_DESCRIPTOR);
+
+ HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
+ NumberOfBytes,
+ USB_HUB_TAG);
+
+ if (!HubDescriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ErrorExit;
+ }
+
+ RtlZeroMemory(HubDescriptor, NumberOfBytes);
+
+ RequestValue = 0;
+ Retry = 0;
+
+ while (TRUE)
+ {
+ while (Retry <= 5)
+ {
+ BM_REQUEST_TYPE RequestType;
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_DEVICE;
+ RequestType.Type = BMREQUEST_STANDARD;
+ RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
+
+ Status = USBH_Transact(HubExtension,
+ HubDescriptor,
+ NumberOfBytes,
+ BMREQUEST_DEVICE_TO_HOST,
+ URB_FUNCTION_CLASS_DEVICE,
+ RequestType,
+ USB_REQUEST_GET_DESCRIPTOR,
+ RequestValue,
+ 0);
+
+ if (NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ RequestValue = 0x2900; // Hub DescriptorType - 0x29
+
+ Retry++;
+ }
+
+ if (HubDescriptor->bDescriptorLength <= NumberOfBytes)
+ {
+ break;
+ }
+
+ NumberOfBytes = HubDescriptor->bDescriptorLength;
+ ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
+
+ if (Retry >= 5)
+ {
+ Status = STATUS_DEVICE_DATA_ERROR;
+ HubDescriptor = NULL;
+ goto ErrorExit;
+ }
+
+ HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
+ NumberOfBytes,
+ USB_HUB_TAG);
+
+ if (!HubDescriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ErrorExit;
+ }
+
+ RtlZeroMemory(HubDescriptor, NumberOfBytes);
+ }
+
+ NumberPorts = HubDescriptor->bNumberOfPorts;
+
+ if (HubExtension->PortData)
+ {
+ PortData = HubExtension->PortData;
+
+ for (ix = 0; ix < NumberPorts; ix++)
+ {
+ PortData[ix].PortStatus.AsULONG = 0;
+
+ if (ExtendedHubInfo)
+ {
+ PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
+ }
+ else
+ {
+ PortData[ix].PortAttributes = 0;
+ }
+
+ PortData[ix].ConnectionStatus = NoDeviceConnected;
+
+ if (PortData[ix].DeviceObject != NULL)
+ {
+ PortData[ix].ConnectionStatus = DeviceConnected;
+ }
+ }
+ }
+ else
+ {
+ PortData = NULL;
+
+ if (HubDescriptor->bNumberOfPorts)
+ {
+ PortData = ExAllocatePoolWithTag(NonPagedPool,
+ NumberPorts * sizeof(USBHUB_PORT_DATA),
+ USB_HUB_TAG);
+ }
+
+ if (!PortData)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ErrorExit;
+ }
+
+ RtlZeroMemory(PortData, NumberPorts * sizeof(USBHUB_PORT_DATA));
+
+ for (ix = 0; ix < NumberPorts; ix++)
+ {
+ PortData[ix].ConnectionStatus = NoDeviceConnected;
+
+ if (ExtendedHubInfo)
+ {
+ PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
+ }
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto ErrorExit;
+ }
+
+ HubExtension->HubDescriptor = HubDescriptor;
+
+ HubExtension->PortData = PortData;
+
+ if (ExtendedHubInfo)
+ {
+ ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
+ }
+
+ return Status;
+
+ErrorExit:
+
+ if (HubDescriptor)
+ {
+ ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
+ }
+
+ if (ExtendedHubInfo)
+ {
+ ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetStringDescriptor(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR Index,
+ IN USHORT LanguageId,
+ IN PUSB_STRING_DESCRIPTOR Descriptor,
+ IN ULONG NumberOfBytes,
+ IN PULONG OutLength,
+ IN BOOLEAN IsValidateLength)
+{
+ struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
+ ULONG TransferedLength;
+ NTSTATUS Status;
+
+ DPRINT("USBH_SyncGetStringDescriptor: Index - %x, LanguageId - %x\n",
+ Index,
+ LanguageId);
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+ USB_HUB_TAG);
+
+ if (!Urb)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ 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 = Descriptor;
+ Urb->TransferBufferLength = NumberOfBytes;
+
+ Urb->Index = Index;
+ Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE;
+ Urb->LanguageId = LanguageId;
+
+ Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+ return Status;
+ }
+
+ TransferedLength = Urb->TransferBufferLength;
+
+ if (TransferedLength > NumberOfBytes)
+ {
+ Status = STATUS_DEVICE_DATA_ERROR;
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+ return Status;
+ }
+
+ if (OutLength)
+ {
+ *OutLength = TransferedLength;
+ }
+
+ if (IsValidateLength && TransferedLength != Descriptor->bLength)
+ {
+ Status = STATUS_DEVICE_DATA_ERROR;
+ }
+
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetStatus(IN PDEVICE_OBJECT DeviceObject,
+ IN PUSHORT OutStatus,
+ IN USHORT Function,
+ IN USHORT RequestIndex)
+{
+ struct _URB_CONTROL_GET_STATUS_REQUEST * Urb;
+ NTSTATUS NtStatus;
+ USHORT UsbStatus;
+
+ DPRINT("USBH_SyncGetStatus: ... \n");
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST),
+ USB_HUB_TAG);
+
+ if (!Urb)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST));
+
+ Urb->Hdr.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
+ Urb->Hdr.Function = Function;
+
+ Urb->TransferBuffer = &UsbStatus;
+ Urb->TransferBufferLength = sizeof(UsbStatus);
+ Urb->Index = RequestIndex;
+
+ NtStatus = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
+
+ *OutStatus = UsbStatus;
+
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+ return NtStatus;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN PUSBHUB_PORT_STATUS PortStatus,
+ IN ULONG Length)
+{
+ BM_REQUEST_TYPE RequestType;
+
+ DPRINT("USBH_SyncGetPortStatus: Port - %x\n", Port);
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_OTHER;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
+
+ return USBH_Transact(HubExtension,
+ PortStatus,
+ Length,
+ BMREQUEST_DEVICE_TO_HOST,
+ URB_FUNCTION_CLASS_OTHER,
+ RequestType,
+ USB_REQUEST_GET_STATUS,
+ 0,
+ Port);
+}
+
+
+NTSTATUS
+NTAPI
+USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN USHORT RequestValue)
+{
+ BM_REQUEST_TYPE RequestType;
+
+ DPRINT("USBH_SyncClearPortStatus: Port - %x, RequestValue - %x\n",
+ Port,
+ RequestValue);
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_DEVICE;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+ return USBH_Transact(HubExtension,
+ NULL,
+ 0,
+ BMREQUEST_HOST_TO_DEVICE,
+ URB_FUNCTION_CLASS_OTHER,
+ RequestType,
+ USB_REQUEST_CLEAR_FEATURE,
+ RequestValue,
+ Port);
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN BOOLEAN IsWait)
+{
+ PUSBHUB_PORT_DATA PortData;
+ PUSB_HUB_DESCRIPTOR HubDescriptor;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BM_REQUEST_TYPE RequestType;
+ PUSBHUB_PORT_STATUS PortStatus;
+
+ DPRINT("USBH_SyncPowerOnPort: Port - %x, IsWait - %x\n", Port, IsWait);
+
+ ASSERT(Port > 0);
+ PortData = &HubExtension->PortData[Port - 1];
+ PortStatus = &PortData->PortStatus;
+
+ if (PortStatus->UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 1)
+ {
+ return Status;
+ }
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_DEVICE;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+ Status = USBH_Transact(HubExtension,
+ NULL,
+ 0,
+ BMREQUEST_HOST_TO_DEVICE,
+ URB_FUNCTION_CLASS_OTHER,
+ RequestType,
+ USB_REQUEST_SET_FEATURE,
+ USBHUB_FEATURE_PORT_POWER,
+ Port);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (IsWait)
+ {
+ HubDescriptor = HubExtension->HubDescriptor;
+ USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
+ }
+
+ PortStatus->UsbPortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSB_HUB_DESCRIPTOR HubDescriptor;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ USHORT Port;
+ UCHAR NumberOfPorts;
+
+ DPRINT("USBH_SyncPowerOnPorts: ... \n");
+
+ HubDescriptor = HubExtension->HubDescriptor;
+ NumberOfPorts = HubDescriptor->bNumberOfPorts;
+
+ for (Port = 1; Port <= NumberOfPorts; ++Port)
+ {
+ Status = USBH_SyncPowerOnPort(HubExtension, Port, 0);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_SyncPowerOnPorts: USBH_SyncPowerOnPort() failed - %lX\n",
+ Status);
+ break;
+ }
+ }
+
+ USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port)
+{
+ PUSBHUB_PORT_DATA PortData;
+ NTSTATUS Status;
+ BM_REQUEST_TYPE RequestType;
+
+ DPRINT("USBH_SyncDisablePort ... \n");
+
+ PortData = &HubExtension->PortData[Port - 1];
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_DEVICE;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+ Status = USBH_Transact(HubExtension,
+ NULL,
+ 0,
+ BMREQUEST_HOST_TO_DEVICE,
+ URB_FUNCTION_CLASS_OTHER,
+ RequestType,
+ USB_REQUEST_CLEAR_FEATURE,
+ USBHUB_FEATURE_PORT_ENABLE,
+ Port);
+
+ if (NT_SUCCESS(Status))
+ {
+ PortData->PortStatus.UsbPortStatus.Usb20PortStatus.PortEnabledDisabled = 0;
+ }
+
+ return Status;
+}
+
+BOOLEAN
+NTAPI
+USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor)
+{
+ BOOLEAN Result;
+ USHORT UsbStatus;
+ NTSTATUS Status;
+
+ DPRINT("USBH_HubIsBusPowered: ... \n");
+
+ Status = USBH_SyncGetStatus(DeviceObject,
+ &UsbStatus,
+ URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+ 0);
+
+ if (!NT_SUCCESS(Status))
+ {
+ Result = (HubConfigDescriptor->bmAttributes & USB_CONFIG_POWERED_MASK)
+ == USB_CONFIG_BUS_POWERED;
+ }
+ else
+ {
+ Result = (UsbStatus & USB_GETSTATUS_SELF_POWERED) == 0;
+ }
+
+ return Result;
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PVOID Event;
+ USHORT Port;
+
+ HubExtension = Context;
+
+ DPRINT_SCE("USBH_ChangeIndicationAckChangeComplete: ... \n");
+
+ ASSERT(HubExtension->Port > 0);
+ Port = HubExtension->Port - 1;
+
+ HubExtension->PortData[Port].PortStatus = HubExtension->PortStatus;
+
+ Event = InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+ NULL);
+
+ if (Event)
+ {
+ KeSetEvent(Event, EVENT_INCREMENT, FALSE);
+ }
+
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+
+ if (!InterlockedDecrement(&HubExtension->ResetRequestCount))
+ {
+ KeSetEvent(&HubExtension->ResetEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
+ IN USHORT Port,
+ IN USHORT RequestValue)
+{
+ PIO_STACK_LOCATION IoStack;
+ BM_REQUEST_TYPE RequestType;
+
+ DPRINT_SCE("USBH_ChangeIndicationAckChange: ... \n");
+
+ Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+ Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
+ Urb->Hdr.UsbdDeviceHandle = NULL;
+
+ Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
+ Urb->TransferBufferLength = 0;
+ Urb->TransferBuffer = NULL;
+ Urb->TransferBufferMDL = NULL;
+ Urb->UrbLink = NULL;
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_OTHER;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+ Urb->RequestTypeReservedBits = RequestType.B;
+ Urb->Request = USB_REQUEST_CLEAR_FEATURE;
+ Urb->Index = Port;
+ Urb->Value = RequestValue;
+
+ IoInitializeIrp(Irp,
+ IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
+ HubExtension->LowerDevice->StackSize);
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.Others.Argument1 = Urb;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(Irp,
+ USBH_ChangeIndicationAckChangeComplete,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ return IoCallDriver(HubExtension->LowerDevice, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PUSBHUB_IO_WORK_ITEM WorkItem;
+ USHORT RequestValue;
+
+ HubExtension = Context;
+
+ DPRINT_SCE("USBH_ChangeIndicationProcessChange: PortStatus - %lX\n",
+ HubExtension->PortStatus.AsULONG);
+
+ if ((NT_SUCCESS(Irp->IoStatus.Status) ||
+ USBD_SUCCESS(HubExtension->SCEWorkerUrb.Hdr.Status)) &&
+ (HubExtension->PortStatus.UsbPortStatusChange.ResetChange ||
+ HubExtension->PortStatus.UsbPortStatusChange.PortEnableDisableChange))
+ {
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ USBH_FreeWorkItem(HubExtension->WorkItemToQueue);
+
+ HubExtension->WorkItemToQueue = NULL;
+
+ if (HubExtension->PortStatus.UsbPortStatusChange.ResetChange)
+ {
+ RequestValue = USBHUB_FEATURE_C_PORT_RESET;
+ }
+ else
+ {
+ RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
+ }
+
+ USBH_ChangeIndicationAckChange(HubExtension,
+ HubExtension->ResetPortIrp,
+ &HubExtension->SCEWorkerUrb,
+ HubExtension->Port,
+ RequestValue);
+ }
+ else
+ {
+ ASSERT(HubExtension->WorkItemToQueue != NULL);
+
+ WorkItem = HubExtension->WorkItemToQueue;
+ HubExtension->WorkItemToQueue = NULL;
+
+ USBH_QueueWorkItem(HubExtension, WorkItem);
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
+ IN USHORT Port)
+{
+ PUSBHUB_IO_WORK_ITEM WorkItem;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ BM_REQUEST_TYPE RequestType;
+
+ DPRINT_SCE("USBH_ChangeIndicationQueryChange: Port - %x\n", Port);
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ if (!Port)
+ {
+ ASSERT(HubExtension->WorkItemToQueue != NULL);
+
+ WorkItem = HubExtension->WorkItemToQueue;
+ HubExtension->WorkItemToQueue = NULL;
+
+ USBH_QueueWorkItem(HubExtension, WorkItem);
+
+ return STATUS_SUCCESS;
+ }
+
+ Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+ Urb->Hdr.UsbdDeviceHandle = NULL;
+ Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
+
+ Urb->TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
+ Urb->TransferBuffer = &HubExtension->PortStatus;
+ Urb->TransferBufferLength = sizeof(HubExtension->PortStatus);
+ Urb->TransferBufferMDL = NULL;
+ Urb->UrbLink = NULL;
+
+ RequestType.B = 0;
+ RequestType.Recipient = BMREQUEST_TO_OTHER;
+ RequestType.Type = BMREQUEST_CLASS;
+ RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
+
+ Urb->RequestTypeReservedBits = RequestType.B;
+ Urb->Request = USB_REQUEST_GET_STATUS;
+ Urb->Value = 0;
+ Urb->Index = Port;
+
+ HubExtension->Port = Port;
+
+ IoInitializeIrp(Irp,
+ IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
+ HubExtension->LowerDevice->StackSize);
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.Others.Argument1 = Urb;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(Irp,
+ USBH_ChangeIndicationProcessChange,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN PUSBHUB_PORT_STATUS PortStatus)
+{
+ PUSBHUB_PORT_DATA PortData;
+ USB_PORT_STATUS_CHANGE PortStatusChange;
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PVOID SerialNumber;
+ PVOID DeviceHandle;
+ USHORT RequestValue;
+ KIRQL Irql;
+
+ DPRINT_SCE("USBH_ProcessPortStateChange ... \n");
+
+ ASSERT(Port > 0);
+ PortData = &HubExtension->PortData[Port - 1];
+
+ PortStatusChange = PortStatus->UsbPortStatusChange;
+
+ if (PortStatusChange.ConnectStatusChange)
+ {
+ PortData->PortStatus.AsULONG = *(PULONG)PortStatus;
+
+ USBH_SyncClearPortStatus(HubExtension,
+ Port,
+ USBHUB_FEATURE_C_PORT_CONNECTION);
+
+ PortData = &HubExtension->PortData[Port - 1];
+
+ PortDevice = PortData->DeviceObject;
+
+ if (!PortDevice)
+ {
+ IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+ return;
+ }
+
+ PortExtension = PortDevice->DeviceExtension;
+
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
+ {
+ return;
+ }
+
+ KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &Irql);
+
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
+ {
+ KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
+ IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+ return;
+ }
+
+ PortData->DeviceObject = NULL;
+ PortData->ConnectionStatus = NoDeviceConnected;
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_STATE_CHANGING;
+
+ InsertTailList(&HubExtension->PdoList, &PortExtension->PortLink);
+
+ KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
+
+ SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
+ NULL);
+
+ if (SerialNumber)
+ {
+ ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
+ }
+
+ DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
+ NULL);
+
+ if (DeviceHandle)
+ {
+ USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
+ USBH_SyncDisablePort(HubExtension, Port);
+ }
+
+ IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+ }
+ else if (PortStatusChange.PortEnableDisableChange)
+ {
+ RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
+ PortData->PortStatus = *PortStatus;
+ USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
+ return;
+ }
+ else if (PortStatusChange.SuspendChange)
+ {
+ DPRINT1("USBH_ProcessPortStateChange: SuspendChange UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+ else if (PortStatusChange.OverCurrentIndicatorChange)
+ {
+ DPRINT1("USBH_ProcessPortStateChange: OverCurrentIndicatorChange UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+ else if (PortStatusChange.ResetChange)
+ {
+ RequestValue = USBHUB_FEATURE_C_PORT_RESET;
+ PortData->PortStatus = *PortStatus;
+ USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
+ }
+}
+
+NTSTATUS
+NTAPI
+USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PULONG PortStatus)
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ DPRINT("USBH_GetPortStatus ... \n");
+
+ *PortStatus = 0;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
+ HubExtension->LowerDevice,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+
+ if (!Irp)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+ IoStack->Parameters.Others.Argument1 = PortStatus;
+
+ Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ else
+ {
+ IoStatusBlock.Status = Status;
+ }
+
+ return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PIRP Irp;
+ NTSTATUS Status;
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ DPRINT("USBH_EnableParentPort ... \n");
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_ENABLE_PORT,
+ HubExtension->LowerDevice,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+
+ if (!Irp)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ else
+ {
+ IoStatusBlock.Status = Status;
+ }
+
+ return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ struct _URB_PIPE_REQUEST * Urb;
+ NTSTATUS Status;
+
+ DPRINT("USBH_ResetInterruptPipe ... \n");
+
+ Urb = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct _URB_PIPE_REQUEST),
+ USB_HUB_TAG);
+
+ if (Urb)
+ {
+ RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
+
+ Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
+ Urb->Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
+ Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
+
+ Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
+ (PURB)Urb);
+
+ ExFreePoolWithTag(Urb, USB_HUB_TAG);
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ HubExtension->RequestErrors = 0;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ NTSTATUS Status;
+ ULONG PortStatusFlags = 0;
+
+ DPRINT("USBH_ResetHub: ... \n");
+
+ Status = USBH_GetPortStatus(HubExtension, &PortStatusFlags);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ if (!(PortStatusFlags & USBD_PORT_ENABLED))
+ {
+ if (PortStatusFlags & USBD_PORT_CONNECTED)
+ {
+ USBH_EnableParentPort(HubExtension);
+ }
+ }
+
+ Status = USBH_ResetInterruptPipe(HubExtension);
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION LowerHubExtension;
+ PUSBHUB_PORT_PDO_EXTENSION LowerPortExtension;
+ PUSBHUB_STATUS_CHANGE_CONTEXT WorkItem;
+ USBHUB_PORT_STATUS PortStatus;
+ NTSTATUS Status;
+ USHORT Port = 0;
+
+ DPRINT_SCE("USBH_ChangeIndicationWorker ... \n");
+
+ WorkItem = Context;
+
+ KeWaitForSingleObject(&HubExtension->HubSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING)
+ {
+ KeSetEvent(&HubExtension->StatusChangeEvent,
+ EVENT_INCREMENT,
+ FALSE);
+
+ goto Exit;
+ }
+
+ if (!HubExtension->RequestErrors)
+ {
+ goto Enum;
+ }
+
+ DPRINT_SCE("USBH_ChangeIndicationWorker: RequestErrors - %x\n",
+ HubExtension->RequestErrors);
+
+ if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
+ {
+ goto Enum;
+ }
+
+ LowerPortExtension = HubExtension->LowerPDO->DeviceExtension;
+
+ if (LowerPortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D1_OR_D2)
+ {
+ goto Enum;
+ }
+
+ LowerHubExtension = LowerPortExtension->HubExtension;
+
+ if (!LowerHubExtension)
+ {
+ goto Enum;
+ }
+
+ Status = USBH_SyncGetPortStatus(LowerHubExtension,
+ LowerPortExtension->PortNumber,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if (!NT_SUCCESS(Status) ||
+ !PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus)
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
+
+ KeSetEvent(&HubExtension->StatusChangeEvent,
+ EVENT_INCREMENT,
+ FALSE);
+
+ goto Exit;
+ }
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING))
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_ESD_RECOVERING;
+
+ DPRINT1("USBH_ChangeIndicationWorker: USBHUB_FDO_FLAG_ESD_RECOVERING FIXME\n");
+ DbgBreakPoint();
+
+ goto Exit;
+ }
+
+Enum:
+
+ if (WorkItem->IsRequestErrors)
+ {
+ USBH_ResetHub(HubExtension);
+ }
+ else
+ {
+ for (Port = 0;
+ Port < HubExtension->HubDescriptor->bNumberOfPorts;
+ Port++)
+ {
+ if (IsBitSet((PUCHAR)(WorkItem + 1), Port))
+ {
+ break;
+ }
+ }
+
+ if (Port)
+ {
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+ }
+ else
+ {
+ DPRINT1("USBH_ChangeIndicationWorker: USBH_SyncGetHubStatus() UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ Status = STATUS_ASSERTION_FAILURE;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ if (Port)
+ {
+ USBH_ProcessPortStateChange(HubExtension,
+ Port,
+ &PortStatus);
+ }
+ else
+ {
+ DPRINT1("USBH_ChangeIndicationWorker: USBH_ProcessHubStateChange() UNIMPLEMENTED. FIXME\n");
+ DbgBreakPoint();
+ }
+ }
+ else
+ {
+ HubExtension->RequestErrors++;
+
+ if (HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS)
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+ goto Exit;
+ }
+ }
+ }
+
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+
+Exit:
+
+ KeReleaseSemaphore(&HubExtension->HubSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ if (!InterlockedDecrement((PLONG)&HubExtension->ResetRequestCount))
+ {
+ KeSetEvent(&HubExtension->ResetEvent,
+ EVENT_INCREMENT,
+ FALSE);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEFER_CHECK_IDLE)
+ {
+ USBH_CheckHubIdle(HubExtension);
+ }
+ }
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ USBD_STATUS UrbStatus;
+ BOOLEAN IsErrors = FALSE;
+ PUSBHUB_IO_WORK_ITEM HubWorkItem;
+ PUSBHUB_STATUS_CHANGE_CONTEXT HubWorkItemBuffer;
+ USHORT NumPorts;
+ USHORT Port;
+ NTSTATUS Status;
+ PVOID Bitmap;
+ ULONG BufferLength;
+
+ HubExtension = Context;
+ UrbStatus = HubExtension->SCEWorkerUrb.Hdr.Status;
+
+ DPRINT_SCE("USBH_ChangeIndication: IrpStatus - %x, UrbStatus - %x, HubFlags - %lX\n",
+ Irp->IoStatus.Status,
+ UrbStatus,
+ HubExtension->HubFlags);
+
+ if (NT_ERROR(Irp->IoStatus.Status) || USBD_ERROR(UrbStatus) ||
+ (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) ||
+ (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING))
+ {
+ HubExtension->RequestErrors++;
+
+ IsErrors = TRUE;
+
+ KeSetEvent(&HubExtension->StatusChangeEvent,
+ EVENT_INCREMENT,
+ FALSE);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
+ HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS ||
+ Irp->IoStatus.Status == STATUS_DELETE_PENDING)
+ {
+ DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
+ HubExtension->RequestErrors);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
+ HubExtension->RequestErrors);
+ }
+ else
+ {
+ HubExtension->RequestErrors = 0;
+ }
+
+ BufferLength = sizeof(USBHUB_STATUS_CHANGE_CONTEXT) +
+ HubExtension->SCEBitmapLength;
+
+ Status = USBH_AllocateWorkItem(HubExtension,
+ &HubWorkItem,
+ USBH_ChangeIndicationWorker,
+ BufferLength,
+ (PVOID *)&HubWorkItemBuffer,
+ DelayedWorkQueue);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ RtlZeroMemory(HubWorkItemBuffer, BufferLength);
+
+ HubWorkItemBuffer->IsRequestErrors = FALSE;
+
+ if (IsErrors)
+ {
+ HubWorkItemBuffer->IsRequestErrors = TRUE;
+ }
+
+ if (InterlockedIncrement(&HubExtension->ResetRequestCount) == 1)
+ {
+ KeResetEvent(&HubExtension->ResetEvent);
+ }
+
+ HubWorkItemBuffer->HubExtension = HubExtension;
+
+ HubExtension->WorkItemToQueue = HubWorkItem;
+
+ Bitmap = HubWorkItemBuffer + 1;
+
+ RtlCopyMemory(Bitmap,
+ HubExtension->SCEBitmap,
+ HubExtension->SCEBitmapLength);
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ for (Port = 0; Port <= NumPorts; ++Port)
+ {
+ if (IsBitSet(Bitmap, Port))
+ {
+ break;
+ }
+ }
+
+ if (Port > NumPorts)
+ {
+ Port = 0;
+ }
+
+ Status = USBH_ChangeIndicationQueryChange(HubExtension,
+ HubExtension->ResetPortIrp,
+ &HubExtension->SCEWorkerUrb,
+ Port);
+
+ if (NT_ERROR(Status))
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PIRP Irp;
+ NTSTATUS Status;
+ struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb;
+ PIO_STACK_LOCATION IoStack;
+
+ DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubExtension - %p, SCEIrp - %p\n",
+ HubExtension,
+ HubExtension->SCEIrp);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_NOT_D0_STATE)
+ {
+ DPRINT_SCE("USBH_SubmitStatusChangeTransfer: USBHUB_FDO_FLAG_NOT_D0_STATE\n");
+ DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubFlags - %lX\n",
+ HubExtension->HubFlags);
+
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ Irp = HubExtension->SCEIrp;
+
+ if (!Irp)
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ Urb = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)&HubExtension->SCEWorkerUrb;
+
+ Urb->Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
+ Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
+ Urb->Hdr.UsbdDeviceHandle = NULL;
+
+ Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
+ Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
+ Urb->TransferBuffer = HubExtension->SCEBitmap;
+ Urb->TransferBufferLength = HubExtension->SCEBitmapLength;
+ Urb->TransferBufferMDL = NULL;
+ Urb->UrbLink = NULL;
+
+ IoInitializeIrp(Irp,
+ IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
+ HubExtension->LowerDevice->StackSize);
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.Others.Argument1 = &HubExtension->SCEWorkerUrb;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(Irp,
+ USBH_ChangeIndication,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ KeResetEvent(&HubExtension->StatusChangeEvent);
+
+ Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE * OutDeviceHandle,
+ IN USB_PORT_STATUS UsbPortStatus,
+ IN USHORT Port)
+{
+ PUSB_DEVICE_HANDLE HubDeviceHandle;
+ PUSB_BUSIFFN_CREATE_USB_DEVICE CreateUsbDevice;
+
+ DPRINT("USBD_CreateDeviceEx: Port - %x, UsbPortStatus - 0x%04X\n",
+ Port,
+ UsbPortStatus.AsUshort16);
+
+ CreateUsbDevice = HubExtension->BusInterface.CreateUsbDevice;
+
+ if (!CreateUsbDevice)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ HubDeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
+
+ return CreateUsbDevice(HubExtension->BusInterface.BusContext,
+ OutDeviceHandle,
+ HubDeviceHandle,
+ UsbPortStatus.AsUshort16,
+ Port);
+}
+
+NTSTATUS
+NTAPI
+USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE DeviceHandle,
+ IN ULONG Flags)
+{
+ PUSB_BUSIFFN_REMOVE_USB_DEVICE RemoveUsbDevice;
+
+ DPRINT("USBD_RemoveDeviceEx: DeviceHandle - %p, Flags - %X\n",
+ DeviceHandle,
+ Flags);
+
+ RemoveUsbDevice = HubExtension->BusInterface.RemoveUsbDevice;
+
+ if (!RemoveUsbDevice)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ return RemoveUsbDevice(HubExtension->BusInterface.BusContext,
+ DeviceHandle,
+ Flags);
+}
+
+NTSTATUS
+NTAPI
+USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE DeviceHandle,
+ IN PUCHAR DeviceDescriptorBuffer,
+ IN ULONG DeviceDescriptorBufferLength,
+ IN PUCHAR ConfigDescriptorBuffer,
+ IN ULONG ConfigDescriptorBufferLength)
+{
+ NTSTATUS Status;
+ PUSB_BUSIFFN_INITIALIZE_USB_DEVICE InitializeUsbDevice;
+ PUSB_BUSIFFN_GET_USB_DESCRIPTORS GetUsbDescriptors;
+
+ DPRINT("USBD_InitializeDeviceEx: ... \n");
+
+ InitializeUsbDevice = HubExtension->BusInterface.InitializeUsbDevice;
+ GetUsbDescriptors = HubExtension->BusInterface.GetUsbDescriptors;
+
+ if (!InitializeUsbDevice || !GetUsbDescriptors)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ Status = InitializeUsbDevice(HubExtension->BusInterface.BusContext,
+ DeviceHandle);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ return GetUsbDescriptors(HubExtension->BusInterface.BusContext,
+ DeviceHandle,
+ DeviceDescriptorBuffer,
+ &DeviceDescriptorBufferLength,
+ ConfigDescriptorBuffer,
+ &ConfigDescriptorBufferLength);
+}
+
+VOID
+NTAPI
+USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PDEVICE_OBJECT UsbDevicePdo,
+ IN PVOID DeviceHandle)
+{
+ PUSB_BUSIFFN_SET_DEVHANDLE_DATA SetDeviceHandleData;
+
+ DPRINT("USBHUB_SetDeviceHandleData ... \n");
+
+ SetDeviceHandleData = HubExtension->BusInterface.SetDeviceHandleData;
+
+ if (!SetDeviceHandleData)
+ {
+ return;
+ }
+
+ SetDeviceHandleData(HubExtension->BusInterface.BusContext,
+ DeviceHandle,
+ UsbDevicePdo);
+}
+
+VOID
+NTAPI
+USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSB_BUSIFFN_FLUSH_TRANSFERS FlushTransfers;
+
+ DPRINT("USBHUB_FlushAllTransfers ... \n");
+
+ FlushTransfers = HubExtension->BusInterface.FlushTransfers;
+
+ if (FlushTransfers)
+ {
+ FlushTransfers(HubExtension->BusInterface.BusContext, NULL);
+ }
+}
+
+NTSTATUS
+NTAPI
+USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,
+ IN ULONG Length,
+ IN PUSB_DEVICE_HANDLE DeviceHandle)
+{
+ PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
+ PUSB_DEVICE_INFORMATION_0 DeviceInfo;
+ SIZE_T DeviceInfoLength;
+ PUSB_NODE_CONNECTION_INFORMATION_EX NodeInfo;
+ SIZE_T NodeInfoLength;
+ ULONG PipeNumber;
+ ULONG dummy;
+ NTSTATUS Status;
+
+ DPRINT("USBD_GetDeviceInformationEx ... \n");
+
+ QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
+
+ if (!QueryDeviceInformation)
+ {
+ Status = STATUS_NOT_IMPLEMENTED;
+ return Status;
+ }
+
+ DeviceInfoLength = sizeof(USB_DEVICE_INFORMATION_0);
+
+ while (TRUE)
+ {
+ DeviceInfo = ExAllocatePoolWithTag(PagedPool,
+ DeviceInfoLength,
+ USB_HUB_TAG);
+
+ if (!DeviceInfo)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(DeviceInfo, DeviceInfoLength);
+
+ DeviceInfo->InformationLevel = 0;
+
+ Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
+ DeviceHandle,
+ DeviceInfo,
+ DeviceInfoLength,
+ &dummy);
+
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ break;
+ }
+
+ DeviceInfoLength = DeviceInfo->ActualLength;
+
+ ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+ }
+
+ NodeInfo = NULL;
+ NodeInfoLength = 0;
+
+ if (NT_SUCCESS(Status))
+ {
+ NodeInfoLength = (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO)) +
+ DeviceInfo->NumberOfOpenPipes * sizeof(USB_PIPE_INFO);
+
+ NodeInfo = ExAllocatePoolWithTag(PagedPool, NodeInfoLength, USB_HUB_TAG);
+
+ if (!NodeInfo)
+ {
+ ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(NodeInfo, NodeInfoLength);
+
+ NodeInfo->ConnectionIndex = Info->ConnectionIndex;
+
+ RtlCopyMemory(&NodeInfo->DeviceDescriptor,
+ &DeviceInfo->DeviceDescriptor,
+ sizeof(USB_DEVICE_DESCRIPTOR));
+
+ NodeInfo->CurrentConfigurationValue = DeviceInfo->CurrentConfigurationValue;
+ NodeInfo->Speed = DeviceInfo->DeviceSpeed;
+ NodeInfo->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE;
+ NodeInfo->DeviceAddress = DeviceInfo->DeviceAddress;
+ NodeInfo->NumberOfOpenPipes = DeviceInfo->NumberOfOpenPipes;
+ NodeInfo->ConnectionStatus = Info->ConnectionStatus;
+
+ for (PipeNumber = 0;
+ PipeNumber < DeviceInfo->NumberOfOpenPipes;
+ PipeNumber++)
+ {
+ RtlCopyMemory(&NodeInfo->PipeList[PipeNumber],
+ &DeviceInfo->PipeList[PipeNumber],
+ sizeof(USB_PIPE_INFO));
+ }
+ }
+
+ ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+
+ if (NodeInfo)
+ {
+ if (NodeInfoLength <= Length)
+ {
+ Length = NodeInfoLength;
+ }
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ RtlCopyMemory(Info, NodeInfo, Length);
+
+ ExFreePoolWithTag(NodeInfo, USB_HUB_TAG);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
+ IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle)
+{
+ PUSB_BUSIFFN_RESTORE_DEVICE RestoreUsbDevice;
+ NTSTATUS Status;
+
+ DPRINT("USBD_RestoreDeviceEx: HubExtension - %p, OldDeviceHandle - %p, NewDeviceHandle - %p\n",
+ HubExtension,
+ OldDeviceHandle,
+ NewDeviceHandle);
+
+ RestoreUsbDevice = HubExtension->BusInterface.RestoreUsbDevice;
+
+ if (RestoreUsbDevice)
+ {
+ Status = RestoreUsbDevice(HubExtension->BusInterface.BusContext,
+ OldDeviceHandle,
+ NewDeviceHandle);
+ }
+ else
+ {
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension,
+ PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,
+ PUSBHUB_WORKER_ROUTINE WorkerRoutine,
+ SIZE_T BufferLength,
+ PVOID * OutHubWorkItemBuffer,
+ WORK_QUEUE_TYPE Type)
+{
+ PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+ PIO_WORKITEM WorkItem;
+ PVOID WorkItemBuffer;
+
+ DPRINT("USBH_AllocateWorkItem: ... \n");
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WITEM_INIT))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ HubIoWorkItem = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(USBHUB_IO_WORK_ITEM),
+ USB_HUB_TAG);
+
+ if (!HubIoWorkItem)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(HubIoWorkItem, sizeof(USBHUB_IO_WORK_ITEM));
+
+ WorkItem = IoAllocateWorkItem(HubExtension->Common.SelfDevice);
+
+ HubIoWorkItem->HubWorkItem = WorkItem;
+
+ if (!WorkItem)
+ {
+ ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (BufferLength && OutHubWorkItemBuffer)
+ {
+ WorkItemBuffer = ExAllocatePoolWithTag(NonPagedPool,
+ BufferLength,
+ USB_HUB_TAG);
+
+ HubIoWorkItem->HubWorkItemBuffer = WorkItemBuffer;
+
+ if (!WorkItemBuffer)
+ {
+ IoFreeWorkItem(HubIoWorkItem->HubWorkItem);
+ ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(WorkItemBuffer, BufferLength);
+ }
+ else
+ {
+ HubIoWorkItem->HubWorkItemBuffer = NULL;
+ }
+
+ HubIoWorkItem->HubWorkItemType = Type;
+ HubIoWorkItem->HubExtension = HubExtension;
+ HubIoWorkItem->HubWorkerRoutine = WorkerRoutine;
+
+ if (OutHubIoWorkItem)
+ {
+ *OutHubIoWorkItem = HubIoWorkItem;
+ }
+
+ if (OutHubWorkItemBuffer)
+ {
+ *OutHubWorkItemBuffer = HubIoWorkItem->HubWorkItemBuffer;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+USBH_Worker(IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context)
+{
+ PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ KIRQL OldIrql;
+ PIO_WORKITEM WorkItem;
+
+ DPRINT("USBH_Worker: HubIoWorkItem - %p\n", Context);
+
+ HubIoWorkItem = Context;
+
+ InterlockedDecrement(&HubIoWorkItem->HubWorkerQueued);
+
+ HubExtension = HubIoWorkItem->HubExtension;
+ WorkItem = HubIoWorkItem->HubWorkItem;
+
+ HubIoWorkItem->HubWorkerRoutine(HubIoWorkItem->HubExtension,
+ HubIoWorkItem->HubWorkItemBuffer);
+
+ KeAcquireSpinLock(&HubExtension->WorkItemSpinLock, &OldIrql);
+ RemoveEntryList(&HubIoWorkItem->HubWorkItemLink);
+ KeReleaseSpinLock(&HubExtension->WorkItemSpinLock, OldIrql);
+
+ if (HubIoWorkItem->HubWorkItemBuffer)
+ {
+ ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
+ }
+
+ ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ IoFreeWorkItem(WorkItem);
+
+ DPRINT("USBH_Worker: HubIoWorkItem %p complete\n", Context);
+}
+
+VOID
+NTAPI
+USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
+{
+ DPRINT("USBH_QueueWorkItem: ... \n");
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+ InterlockedIncrement(&HubIoWorkItem->HubWorkerQueued);
+
+ ExInterlockedInsertTailList(&HubExtension->WorkItemList,
+ &HubIoWorkItem->HubWorkItemLink,
+ &HubExtension->WorkItemSpinLock);
+
+ IoQueueWorkItem(HubIoWorkItem->HubWorkItem,
+ USBH_Worker,
+ HubIoWorkItem->HubWorkItemType,
+ HubIoWorkItem);
+}
+
+VOID
+NTAPI
+USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
+{
+ PIO_WORKITEM WorkItem;
+
+ DPRINT("USBH_FreeWorkItem: ... \n");
+
+ WorkItem = HubIoWorkItem->HubWorkItem;
+
+ if (HubIoWorkItem->HubWorkItemBuffer)
+ {
+ ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
+ }
+
+ ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+
+ IoFreeWorkItem(WorkItem);
+}
+
+VOID
+NTAPI
+USBHUB_RootHubCallBack(IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+
+ DPRINT("USBHUB_RootHubCallBack: ... \n");
+
+ HubExtension = Context;
+
+ if (HubExtension->SCEIrp)
+ {
+ HubExtension->HubFlags |= (USBHUB_FDO_FLAG_DO_ENUMERATION |
+ USBHUB_FDO_FLAG_NOT_ENUMERATED);
+
+ USBH_SubmitStatusChangeTransfer(HubExtension);
+
+ IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+ }
+ else
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
+ }
+
+ KeSetEvent(&HubExtension->RootHubNotificationEvent,
+ EVENT_INCREMENT,
+ FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
+
+ DPRINT("USBD_RegisterRootHubCallBack: ... \n");
+
+ RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
+
+ if (!RootHubInitNotification)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ KeResetEvent(&HubExtension->RootHubNotificationEvent);
+
+ return RootHubInitNotification(HubExtension->BusInterface.BusContext,
+ HubExtension,
+ USBHUB_RootHubCallBack);
+}
+
+NTSTATUS
+NTAPI
+USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
+ NTSTATUS Status;
+
+ DPRINT("USBD_UnRegisterRootHubCallBack ... \n");
+
+ RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
+
+ if (!RootHubInitNotification)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ Status = RootHubInitNotification(HubExtension->BusInterface.BusContext,
+ NULL,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ KeWaitForSingleObject(&HubExtension->RootHubNotificationEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ DPRINT("USBH_HubSetDWakeCompletion: ... \n");
+ KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PLIST_ENTRY IdleList)
+{
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PIRP IdleIrp;
+ PIRP HubIdleIrp;
+ ULONG NumPorts;
+ ULONG Port;
+ KIRQL Irql;
+
+ DPRINT("USBH_HubQueuePortIdleIrps ... \n");
+
+ InitializeListHead(IdleList);
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+ for (Port = 0; Port < NumPorts; ++Port)
+ {
+ PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+ if (PortDevice)
+ {
+ PortExtension = PortDevice->DeviceExtension;
+
+ IdleIrp = PortExtension->IdleNotificationIrp;
+ PortExtension->IdleNotificationIrp = NULL;
+
+ if (IdleIrp && IoSetCancelRoutine(IdleIrp, NULL))
+ {
+ DPRINT1("USBH_HubQueuePortIdleIrps: IdleIrp != NULL. FIXME\n");
+ DbgBreakPoint();
+ }
+ }
+ }
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+ {
+ HubIdleIrp = HubExtension->PendingIdleIrp;
+ HubExtension->PendingIdleIrp = NULL;
+ }
+ else
+ {
+ HubIdleIrp = NULL;
+ }
+
+ IoReleaseCancelSpinLock(Irql);
+
+ if (HubIdleIrp)
+ {
+ USBH_HubCancelIdleIrp(HubExtension, HubIdleIrp);
+ }
+}
+
+VOID
+NTAPI
+USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PLIST_ENTRY IdleList,
+ IN NTSTATUS NtStatus)
+{
+ DPRINT("USBH_HubCompleteQueuedPortIdleIrps ... \n");
+
+ while (!IsListEmpty(IdleList))
+ {
+ DPRINT1("USBH_HubCompleteQueuedPortIdleIrps: IdleList not Empty. FIXME\n");
+ DbgBreakPoint();
+ }
+}
+
+VOID
+NTAPI
+USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PLIST_ENTRY Entry;
+ ULONG Port;
+
+ DPRINT("USBH_FlushPortPwrList ... \n");
+
+ InterlockedIncrement((PLONG)&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; ++Port)
+ {
+ PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+ if (!PortDevice)
+ {
+ continue;
+ }
+
+ PortExtension = PortDevice->DeviceExtension;
+
+ InterlockedExchange((PLONG)&PortExtension->StateBehindD2, 0);
+
+ while (TRUE)
+ {
+ Entry = ExInterlockedRemoveHeadList(&PortExtension->PortPowerList,
+ &PortExtension->PortPowerListSpinLock);
+
+ if (!Entry)
+ {
+ break;
+ }
+
+ DPRINT1("USBH_FlushPortPwrList: PortPowerList FIXME\n");
+ DbgBreakPoint();
+ }
+ }
+
+ KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement((PLONG)&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+}
+
+VOID
+NTAPI
+USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN NTSTATUS NtStatus)
+{
+ LIST_ENTRY IdleList;
+
+ DPRINT("USBH_HubCompletePortIdleIrps ... \n");
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ USBH_HubQueuePortIdleIrps(HubExtension, &IdleList);
+
+ USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
+ &IdleList,
+ NtStatus);
+
+ USBH_FlushPortPwrList(HubExtension);
+ }
+}
+
+VOID
+NTAPI
+USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP IdleIrp)
+{
+ DPRINT("USBH_HubCancelIdleIrp ... \n");
+
+ IoCancelIrp(IdleIrp);
+
+ if (InterlockedExchange(&HubExtension->IdleRequestLock, 1))
+ {
+ IoFreeIrp(IdleIrp);
+ }
+}
+
+BOOLEAN
+NTAPI
+USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN BOOLEAN IsWait,
+ IN BOOLEAN IsExtCheck)
+{
+ PDEVICE_OBJECT PdoDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PUSBHUB_PORT_DATA PortData;
+ ULONG Port;
+ BOOLEAN Result = FALSE;
+
+ DPRINT("USBH_CheckIdleAbort: ... \n");
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ if (IsWait == TRUE)
+ {
+ KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ PortData = HubExtension->PortData;
+
+ for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
+ {
+ PdoDevice = PortData[Port].DeviceObject;
+
+ if (PdoDevice)
+ {
+ PortExtension = PdoDevice->DeviceExtension;
+
+ if (PortExtension->PoRequestCounter)
+ {
+ Result = TRUE;
+ goto Wait;
+ }
+ }
+ }
+
+ if (IsExtCheck == TRUE)
+ {
+ PortData = HubExtension->PortData;
+
+ for (Port = 0;
+ Port < HubExtension->HubDescriptor->bNumberOfPorts;
+ Port++)
+ {
+ PdoDevice = PortData[Port].DeviceObject;
+
+ if (PdoDevice)
+ {
+ PortExtension = PdoDevice->DeviceExtension;
+ InterlockedExchange(&PortExtension->StateBehindD2, 0);
+ }
+ }
+ }
+
+Wait:
+
+ if (IsWait == TRUE)
+ {
+ KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+ }
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ return Result;
+}
+
+VOID
+NTAPI
+USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID Context,
+ IN PIO_STATUS_BLOCK IoStatus)
+{
+ DPRINT("USBH_FdoWaitWakeIrpCompletion ... \n");
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ POWER_STATE PowerState;
+ NTSTATUS Status;
+ PIRP Irp = NULL;
+ KIRQL Irql;
+
+ DPRINT("USBH_FdoSubmitWaitWakeIrp: ... \n");
+
+ PowerState.SystemState = HubExtension->SystemWake;
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+ InterlockedExchange(&HubExtension->FdoWaitWakeLock, 0);
+
+ Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_WAIT_WAKE,
+ PowerState,
+ USBH_FdoWaitWakeIrpCompletion,
+ HubExtension,
+ &Irp);
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ if (Status == STATUS_PENDING)
+ {
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP)
+ {
+ HubExtension->PendingWakeIrp = Irp;
+ DPRINT("USBH_FdoSubmitWaitWakeIrp: PendingWakeIrp - %p\n",
+ HubExtension->PendingWakeIrp);
+ }
+ }
+ else
+ {
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+ }
+
+ IoReleaseCancelSpinLock(Irql);
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoIdleNotificationCallback(IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PUSBHUB_PORT_DATA PortData;
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PIRP Irp = NULL;
+ PIRP IdleIrp;
+ POWER_STATE PowerState;
+ KEVENT Event;
+ ULONG Port;
+ PIO_STACK_LOCATION IoStack;
+ PUSB_IDLE_CALLBACK_INFO CallbackInfo;
+ BOOLEAN IsReady;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+
+ HubExtension = Context;
+
+ DPRINT("USBH_FdoIdleNotificationCallback: HubExtension - %p, HubFlags - %lX\n",
+ HubExtension,
+ HubExtension->HubFlags);
+
+ if (HubExtension->HubFlags & (USBHUB_FDO_FLAG_ENUM_POST_RECOVER |
+ USBHUB_FDO_FLAG_WAKEUP_START |
+ USBHUB_FDO_FLAG_DEVICE_REMOVED |
+ USBHUB_FDO_FLAG_STATE_CHANGING |
+ USBHUB_FDO_FLAG_ESD_RECOVERING |
+ USBHUB_FDO_FLAG_DEVICE_FAILED |
+ USBHUB_FDO_FLAG_DEVICE_STOPPING))
+ {
+ DbgBreakPoint();
+ return;
+ }
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_GOING_IDLE;
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP))
+ {
+ Status = USBH_FdoSubmitWaitWakeIrp(HubExtension);
+
+ if (Status != STATUS_PENDING)
+ {
+ DPRINT("Status != STATUS_PENDING. DbgBreakPoint()\n");
+ DbgBreakPoint();
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
+ return;
+ }
+ }
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ PortData = HubExtension->PortData;
+ IsReady = TRUE;
+
+ for (Port = 0;
+ Port < HubExtension->HubDescriptor->bNumberOfPorts;
+ Port++)
+ {
+ PortDevice = PortData[Port].DeviceObject;
+
+ if (PortDevice)
+ {
+ PortExtension = PortDevice->DeviceExtension;
+
+ IdleIrp = PortExtension->IdleNotificationIrp;
+
+ if (!IdleIrp)
+ {
+ IsReady = FALSE;
+ goto IdleHub;
+ }
+
+ IoStack = IoGetCurrentIrpStackLocation(IdleIrp);
+
+ CallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ if (!CallbackInfo)
+ {
+ IsReady = FALSE;
+ goto IdleHub;
+ }
+
+ if (!CallbackInfo->IdleCallback)
+ {
+ IsReady = FALSE;
+ goto IdleHub;
+ }
+
+ if (PortExtension->PendingSystemPoRequest)
+ {
+ IsReady = FALSE;
+ goto IdleHub;
+ }
+
+ if (InterlockedCompareExchange(&PortExtension->StateBehindD2,
+ 1,
+ 0))
+ {
+ IsReady = FALSE;
+ goto IdleHub;
+ }
+
+ DPRINT("USBH_FdoIdleNotificationCallback: IdleContext - %p\n",
+ CallbackInfo->IdleContext);
+
+ CallbackInfo->IdleCallback(CallbackInfo->IdleContext);
+
+ if (PortExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
+ {
+ IsReady = FALSE;
+ goto IdleHub;
+ }
+ }
+ }
+
+ if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) &&
+ (USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) == TRUE))
+ {
+ IsReady = FALSE;
+ }
+
+IdleHub:
+
+ KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ if (!IsReady ||
+ (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_SUSPENDED))
+ {
+ DPRINT1("USBH_FdoIdleNotificationCallback: HubFlags - %lX\n",
+ HubExtension->HubFlags);
+
+ HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
+ USBHUB_FDO_FLAG_GOING_IDLE);
+
+ /* Aborting Idle for Hub */
+ IoAcquireCancelSpinLock(&OldIrql);
+
+ if (HubExtension->PendingIdleIrp)
+ {
+ Irp = HubExtension->PendingIdleIrp;
+ HubExtension->PendingIdleIrp = NULL;
+ }
+
+ IoReleaseCancelSpinLock(OldIrql);
+
+ if (Irp)
+ {
+ USBH_HubCancelIdleIrp(HubExtension, Irp);
+ }
+
+ DbgBreakPoint();
+ USBH_HubCompletePortIdleIrps(HubExtension, STATUS_CANCELLED);
+ }
+ else
+ {
+ PowerState.DeviceState = HubExtension->DeviceWake;
+
+ KeWaitForSingleObject(&HubExtension->IdleSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ DPRINT("USBH_FdoIdleNotificationCallback: LowerPdo - %p\n",
+ HubExtension->LowerPDO);
+
+ DPRINT("USBH_FdoIdleNotificationCallback: PowerState.DeviceState - %x\n",
+ PowerState.DeviceState);
+
+ Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+ IRP_MN_SET_POWER,
+ PowerState,
+ USBH_HubSetDWakeCompletion,
+ &Event,
+ NULL);
+
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ }
+}
+
+VOID
+NTAPI
+USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ PUSBHUB_IDLE_PORT_CONTEXT IdlePortContext;
+ NTSTATUS NtStatus;
+ NTSTATUS Status;
+ BOOLEAN IsFlush = FALSE;
+
+ DPRINT("USBH_CompletePortIdleIrpsWorker ... \n");
+
+ IdlePortContext = Context;
+ NtStatus = IdlePortContext->Status;
+
+ USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
+ &IdlePortContext->PwrList,
+ NtStatus);
+
+ DPRINT1("USBH_CompletePortIdleIrpsWorker: USBH_RegQueryFlushPortPowerIrpsFlag() UNIMPLEMENTED. FIXME\n");
+ Status = STATUS_NOT_IMPLEMENTED;// USBH_RegQueryFlushPortPowerIrpsFlag(&IsFlush);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (IsFlush)
+ {
+ USBH_FlushPortPwrList(HubExtension);
+ }
+ }
+}
+
+VOID
+NTAPI
+USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
+
+ DPRINT("USBH_IdleCompletePowerHubWorker ... \n");
+
+ if (HubExtension &&
+ HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+ {
+ USBH_HubSetD0(HubExtension);
+ }
+
+ HubWorkItemBuffer = Context;
+
+ USBH_HubCompletePortIdleIrps(HubExtension, HubWorkItemBuffer->Status);
+
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ NTSTATUS NtStatus;
+ PVOID IdleIrp;
+ KIRQL Irql;
+ NTSTATUS Status;
+ PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ HubExtension = Context;
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+
+ IdleIrp = InterlockedExchangePointer((PVOID)&HubExtension->PendingIdleIrp,
+ NULL);
+
+ DPRINT("USBH_FdoIdleNotificationRequestComplete: IdleIrp - %p\n", IdleIrp);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
+ }
+
+ IoReleaseCancelSpinLock(Irql);
+
+ NtStatus = Irp->IoStatus.Status;
+
+ DPRINT("USBH_FdoIdleNotificationRequestComplete: NtStatus - %lX\n",
+ NtStatus);
+
+ if (!NT_SUCCESS(NtStatus) &&
+ NtStatus != STATUS_POWER_STATE_INVALID &&
+ !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) &&
+ !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+ {
+ DPRINT("USBH_FdoIdleNotificationRequestComplete: DeviceState - %x\n",
+ HubExtension->CurrentPowerState.DeviceState);
+
+ if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
+ {
+ PUSBHUB_IDLE_PORT_CONTEXT HubWorkItemBuffer;
+
+ Status = USBH_AllocateWorkItem(HubExtension,
+ &HubIoWorkItem,
+ USBH_CompletePortIdleIrpsWorker,
+ sizeof(USBHUB_IDLE_PORT_CONTEXT),
+ (PVOID *)&HubWorkItemBuffer,
+ DelayedWorkQueue);
+
+ if (NT_SUCCESS(Status))
+ {
+ HubWorkItemBuffer->Status = NtStatus;
+
+ USBH_HubQueuePortIdleIrps(HubExtension,
+ &HubWorkItemBuffer->PwrList);
+
+ USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+ }
+ }
+ else
+ {
+ PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
+
+ Status = USBH_AllocateWorkItem(HubExtension,
+ &HubIoWorkItem,
+ USBH_IdleCompletePowerHubWorker,
+ sizeof(USBHUB_IDLE_HUB_CONTEXT),
+ (PVOID *)&HubWorkItemBuffer,
+ DelayedWorkQueue);
+
+ if (NT_SUCCESS(Status))
+ {
+ HubWorkItemBuffer->Status = NtStatus;
+ USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+ }
+ }
+ }
+
+ if (IdleIrp ||
+ InterlockedExchange((PLONG)&HubExtension->IdleRequestLock, 1))
+ {
+ DPRINT("USBH_FdoIdleNotificationRequestComplete: Irp - %p\n", Irp);
+ IoFreeIrp(Irp);
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ NTSTATUS Status;
+ ULONG HubFlags;
+ PDEVICE_OBJECT LowerPDO;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ KIRQL Irql;
+
+ DPRINT("USBH_FdoSubmitIdleRequestIrp: HubExtension - %p, PendingIdleIrp - %p\n",
+ HubExtension,
+ HubExtension->PendingIdleIrp);
+
+ if (HubExtension->PendingIdleIrp)
+ {
+ Status = STATUS_DEVICE_BUSY;
+ KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+ return Status;
+ }
+
+ HubFlags = HubExtension->HubFlags;
+
+ if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
+ HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED)
+ {
+ HubExtension->HubFlags = HubFlags & ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+ KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+ return STATUS_DEVICE_REMOVED;
+ }
+
+ LowerPDO = HubExtension->LowerPDO;
+
+ HubExtension->IdleCallbackInfo.IdleCallback = USBH_FdoIdleNotificationCallback;
+ HubExtension->IdleCallbackInfo.IdleContext = HubExtension;
+
+ Irp = IoAllocateIrp(LowerPDO->StackSize, FALSE);
+
+ if (!Irp)
+ {
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+ return Status;
+ }
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+ IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(USB_IDLE_CALLBACK_INFO);
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
+ IoStack->Parameters.DeviceIoControl.Type3InputBuffer = &HubExtension->IdleCallbackInfo;
+
+ IoSetCompletionRoutine(Irp,
+ USBH_FdoIdleNotificationRequestComplete,
+ HubExtension,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+ InterlockedExchange(&HubExtension->IdleRequestLock, 0);
+
+ HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
+ USBHUB_FDO_FLAG_GOING_IDLE);
+
+ Status = IoCallDriver(HubExtension->LowerPDO, Irp);
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ if (Status == STATUS_PENDING &&
+ HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+ {
+ HubExtension->PendingIdleIrp = Irp;
+ }
+
+ IoReleaseCancelSpinLock(Irql);
+
+ KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PDEVICE_OBJECT PdoDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PUSBHUB_PORT_DATA PortData;
+ ULONG HubFlags;
+ ULONG Port;
+ KIRQL Irql;
+ BOOLEAN IsHubIdle = FALSE;
+ BOOLEAN IsAllPortsIdle;
+ BOOLEAN IsHubCheck = TRUE;
+
+ DPRINT("USBH_CheckHubIdle: FIXME !!! HubExtension - %p\n", HubExtension);
+
+return; //HACK: delete it line after fixing Power Manager!!!
+
+ KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
+
+ if (HubExtension->HubFlags & USBHUB_FDO_FLAG_CHECK_IDLE_LOCK)
+ {
+ KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+ return;
+ }
+
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
+ KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+
+ if (USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState != PowerSystemWorking)
+ {
+ KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
+ KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+ return;
+ }
+
+ HubFlags = HubExtension->HubFlags;
+ DPRINT("USBH_CheckHubIdle: HubFlags - %lX\n", HubFlags);
+
+ if (!(HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) ||
+ !(HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
+ {
+ goto Exit;
+ }
+
+ if (HubFlags & USBHUB_FDO_FLAG_NOT_ENUMERATED ||
+ HubFlags & USBHUB_FDO_FLAG_ENUM_POST_RECOVER ||
+ HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
+ HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
+ HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED ||
+ HubFlags & USBHUB_FDO_FLAG_STATE_CHANGING ||
+ HubFlags & USBHUB_FDO_FLAG_WAKEUP_START ||
+ HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
+ {
+ goto Exit;
+ }
+
+ if (HubExtension->ResetRequestCount)
+ {
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
+ goto Exit;
+ }
+
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ IoAcquireCancelSpinLock(&Irql);
+
+ IsAllPortsIdle = TRUE;
+
+ PortData = HubExtension->PortData;
+
+ for (Port = 0;
+ Port < HubExtension->HubDescriptor->bNumberOfPorts;
+ Port++)
+ {
+ PdoDevice = PortData[Port].DeviceObject;
+
+ if (PdoDevice)
+ {
+ PortExtension = PdoDevice->DeviceExtension;
+
+ if (!PortExtension->IdleNotificationIrp)
+ {
+ DPRINT("USBH_CheckHubIdle: PortExtension - %p\n",
+ PortExtension);
+
+ IsAllPortsIdle = FALSE;
+ IsHubCheck = FALSE;
+
+ break;
+ }
+ }
+ }
+
+ if (IsHubCheck &&
+ !(HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST))
+ {
+ KeResetEvent(&HubExtension->IdleEvent);
+ HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+ IsHubIdle = TRUE;
+ }
+
+ IoReleaseCancelSpinLock(Irql);
+
+ KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ DPRINT("USBH_CheckHubIdle: IsAllPortsIdle - %x, IsHubIdle - %x\n",
+ IsAllPortsIdle,
+ IsHubIdle);
+
+ if (IsAllPortsIdle && IsHubIdle)
+ {
+ USBH_FdoSubmitIdleRequestIrp(HubExtension);
+ }
+
+Exit:
+ KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
+ HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
+ KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+}
+
+VOID
+NTAPI
+USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context)
+{
+ DPRINT("USBH_CheckIdleWorker: ... \n");
+ USBH_CheckHubIdle(HubExtension);
+}
+
+VOID
+NTAPI
+USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+ PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+ NTSTATUS Status;
+
+ DPRINT("USBH_CheckIdleDeferred: HubExtension - %p\n", HubExtension);
+
+ Status = USBH_AllocateWorkItem(HubExtension,
+ &HubIoWorkItem,
+ USBH_CheckIdleWorker,
+ 0,
+ NULL,
+ DelayedWorkQueue);
+
+ DPRINT("USBH_CheckIdleDeferred: HubIoWorkItem - %p\n", HubIoWorkItem);
+
+ if (NT_SUCCESS(Status))
+ {
+ USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+ }
+}
+
+VOID
+NTAPI
+USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
+{
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ ULONG State;
+ SYSTEM_POWER_STATE SystemPowerState;
+ PDEVICE_POWER_STATE pDeviceState;
+
+ DPRINT("USBH_PdoSetCapabilities ... \n");
+
+ HubExtension = PortExtension->HubExtension;
+
+ PortExtension->Capabilities.Size = 64;
+ PortExtension->Capabilities.Version = 1;
+
+ PortExtension->Capabilities.Removable = 1;
+ PortExtension->Capabilities.Address = PortExtension->PortNumber;
+
+ if (PortExtension->SerialNumber)
+ {
+ PortExtension->Capabilities.UniqueID = 1;
+ }
+ else
+ {
+ PortExtension->Capabilities.UniqueID = 0;
+ }
+
+ PortExtension->Capabilities.RawDeviceOK = 0;
+
+ RtlCopyMemory(PortExtension->Capabilities.DeviceState,
+ HubExtension->DeviceState,
+ (PowerSystemMaximum + 2) * sizeof(POWER_STATE));
+
+ PortExtension->Capabilities.DeviceState[1] = PowerDeviceD0;
+
+ if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOTE_WAKEUP)
+ {
+ PortExtension->Capabilities.DeviceWake = PowerDeviceD2;
+
+ PortExtension->Capabilities.DeviceD1 = 1;
+ PortExtension->Capabilities.DeviceD2 = 1;
+
+ PortExtension->Capabilities.WakeFromD0 = 1;
+ PortExtension->Capabilities.WakeFromD1 = 1;
+ PortExtension->Capabilities.WakeFromD2 = 1;
+
+ pDeviceState = &PortExtension->Capabilities.DeviceState[2];
+
+ for (State = 2; State <= 5; State++)
+ {
+ SystemPowerState = State;
+
+ if (PortExtension->Capabilities.SystemWake < SystemPowerState)
+ {
+ *pDeviceState = PowerDeviceD3;
+ }
+ else
+ {
+ *pDeviceState = PowerDeviceD2;
+ }
+
+ ++pDeviceState;
+ }
+ }
+ else
+ {
+ PortExtension->Capabilities.DeviceWake = PowerDeviceD0;
+ PortExtension->Capabilities.DeviceState[2] = PowerDeviceD3;
+ PortExtension->Capabilities.DeviceState[3] = PowerDeviceD3;
+ PortExtension->Capabilities.DeviceState[4] = PowerDeviceD3;
+ PortExtension->Capabilities.DeviceState[5] = PowerDeviceD3;
+ }
+}
+
+NTSTATUS
+NTAPI
+USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
+{
+ PUSB_INTERFACE_DESCRIPTOR Pid;
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+ NTSTATUS Status;
+
+ DPRINT("USBH_ProcessDeviceInformation ... \n");
+
+ ConfigDescriptor = NULL;
+
+ RtlZeroMemory(&PortExtension->InterfaceDescriptor,
+ sizeof(PortExtension->InterfaceDescriptor));
+
+ PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_HUB_DEVICE;
+
+ Status = USBH_GetConfigurationDescriptor(PortExtension->Common.SelfDevice,
+ &ConfigDescriptor);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (ConfigDescriptor)
+ {
+ ExFreePool(ConfigDescriptor);
+ }
+
+ return Status;
+ }
+
+ PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOTE_WAKEUP;
+
+ if (ConfigDescriptor->bmAttributes & 0x20)
+ {
+ /* device configuration supports remote wakeup */
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOTE_WAKEUP;
+ }
+
+ USBHUB_DumpingDeviceDescriptor(&PortExtension->DeviceDescriptor);
+ USBHUB_DumpingConfiguration(ConfigDescriptor);
+
+ DPRINT_PNP("USBH_ProcessDeviceInformation: Class - %x, SubClass - %x, Protocol - %x\n",
+ PortExtension->DeviceDescriptor.bDeviceClass,
+ PortExtension->DeviceDescriptor.bDeviceSubClass,
+ PortExtension->DeviceDescriptor.bDeviceProtocol);
+
+ DPRINT_PNP("USBH_ProcessDeviceInformation: bNumConfigurations - %x, bNumInterfaces - %x\n",
+ PortExtension->DeviceDescriptor.bNumConfigurations,
+ ConfigDescriptor->bNumInterfaces);
+
+
+ /* Enumeration of USB Composite Devices (msdn):
+ 1) The device class field of the device descriptor (bDeviceClass) must contain a value of zero,
+ or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol)
+ fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively,
+ as explained in USB Interface Association Descriptor.
+ 2) The device must have multiple interfaces
+ 3) The device must have a single configuration.
+ */
+
+ if (((PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_RESERVED) ||
+ (PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_MISCELLANEOUS &&
+ PortExtension->DeviceDescriptor.bDeviceSubClass == 0x02 &&
+ PortExtension->DeviceDescriptor.bDeviceProtocol == 0x01)) &&
+ (ConfigDescriptor->bNumInterfaces > 1) &&
+ (PortExtension->DeviceDescriptor.bNumConfigurations < 2))
+ {
+ DPRINT("USBH_ProcessDeviceInformation: Multi-Interface configuration\n");
+
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_MULTI_INTERFACE;
+
+ if (ConfigDescriptor)
+ {
+ ExFreePool(ConfigDescriptor);
+ }
+
+ return Status;
+ }
+
+ Pid = USBD_ParseConfigurationDescriptorEx(ConfigDescriptor,
+ ConfigDescriptor,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1);
+ if (Pid)
+ {
+ RtlCopyMemory(&PortExtension->InterfaceDescriptor,
+ Pid,
+ sizeof(PortExtension->InterfaceDescriptor));
+
+ if (Pid->bInterfaceClass == USB_DEVICE_CLASS_HUB)
+ {
+ PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_HUB_DEVICE |
+ USBHUB_PDO_FLAG_REMOTE_WAKEUP);
+ }
+ }
+ else
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ if (ConfigDescriptor)
+ {
+ ExFreePool(ConfigDescriptor);
+ }
+
+ return Status;
+}
+
+BOOLEAN
+NTAPI
+USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT idVendor,
+ IN USHORT idProduct,
+ IN PVOID SerialNumber,
+ IN USHORT SN_DescriptorLength)
+{
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ ULONG Port;
+ SIZE_T NumberBytes;
+
+ DPRINT("USBH_CheckDeviceIDUnique: idVendor - 0x%04X, idProduct - 0x%04X\n",
+ idVendor,
+ idProduct);
+
+ if (!HubExtension->HubDescriptor->bNumberOfPorts)
+ {
+ return TRUE;
+ }
+
+ for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
+ {
+ PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+ if (PortDevice)
+ {
+ PortExtension = PortDevice->DeviceExtension;
+
+ if (PortExtension->DeviceDescriptor.idVendor == idVendor &&
+ PortExtension->DeviceDescriptor.idProduct == idProduct &&
+ PortExtension->SN_DescriptorLength == SN_DescriptorLength)
+ {
+ if (PortExtension->SerialNumber)
+ {
+ NumberBytes = RtlCompareMemory(PortExtension->SerialNumber,
+ SerialNumber,
+ SN_DescriptorLength);
+
+ if (NumberBytes == SN_DescriptorLength)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+NTAPI
+USBH_ValidateSerialNumberString(IN PUSHORT SerialNumberString)
+{
+ USHORT ix;
+ USHORT Symbol;
+
+ DPRINT("USBH_ValidateSerialNumberString: ... \n");
+
+ for (ix = 0; SerialNumberString[ix] != UNICODE_NULL; ix++)
+ {
+ Symbol = SerialNumberString[ix];
+
+ if (Symbol < 0x20 || Symbol > 0x7F || Symbol == 0x2C) // ','
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+NTSTATUS
+NTAPI
+USBH_CheckDeviceLanguage(IN PDEVICE_OBJECT DeviceObject,
+ IN USHORT LanguageId)
+{
+ PUSB_STRING_DESCRIPTOR Descriptor;
+ NTSTATUS Status;
+ ULONG NumSymbols;
+ ULONG ix;
+ PWCHAR pSymbol;
+ ULONG Length;
+
+ DPRINT("USBH_CheckDeviceLanguage: LanguageId - 0x%04X\n", LanguageId);
+
+ Descriptor = ExAllocatePoolWithTag(NonPagedPool,
+ MAXIMUM_USB_STRING_LENGTH,
+ USB_HUB_TAG);
+
+ if (!Descriptor)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
+
+ Status = USBH_SyncGetStringDescriptor(DeviceObject,
+ 0,
+ 0,
+ Descriptor,
+ MAXIMUM_USB_STRING_LENGTH,
+ &Length,
+ TRUE);
+
+ if (!NT_SUCCESS(Status) ||
+ Length < sizeof(USB_COMMON_DESCRIPTOR))
+ {
+ goto Exit;
+ }
+
+ NumSymbols = (Length -
+ FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) / sizeof(WCHAR);
+
+ pSymbol = Descriptor->bString;
+
+ for (ix = 1; ix < NumSymbols; ix++)
+ {
+ if (*pSymbol == (WCHAR)LanguageId)
+ {
+ Status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ pSymbol++;
+ }
+
+ Status = STATUS_NOT_SUPPORTED;
+
+Exit:
+ ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetSerialNumberString(IN PDEVICE_OBJECT DeviceObject,
+ IN LPWSTR * OutSerialNumber,
+ IN PUSHORT OutDescriptorLength,
+ IN USHORT LanguageId,
+ IN UCHAR Index)
+{
+ PUSB_STRING_DESCRIPTOR Descriptor;
+ NTSTATUS Status;
+ LPWSTR SerialNumberBuffer = NULL;
+ UCHAR StringLength;
+ UCHAR Length;
+
+ DPRINT("USBH_GetSerialNumberString: ... \n");
+
+ *OutSerialNumber = NULL;
+ *OutDescriptorLength = 0;
+
+ Descriptor = ExAllocatePoolWithTag(NonPagedPool,
+ MAXIMUM_USB_STRING_LENGTH,
+ USB_HUB_TAG);
+
+ if (!Descriptor)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
+
+ Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Exit;
+ }
+
+ Status = USBH_SyncGetStringDescriptor(DeviceObject,
+ Index,
+ LanguageId,
+ Descriptor,
+ MAXIMUM_USB_STRING_LENGTH,
+ NULL,
+ TRUE);
+
+ if (!NT_SUCCESS(Status) ||
+ Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ StringLength = Descriptor->bLength -
+ FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
+
+ Length = StringLength + sizeof(UNICODE_NULL);
+
+ SerialNumberBuffer = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+ if (!SerialNumberBuffer)
+ {
+ goto Exit;
+ }
+
+ RtlZeroMemory(SerialNumberBuffer, Length);
+ RtlCopyMemory(SerialNumberBuffer, Descriptor->bString, StringLength);
+
+ *OutSerialNumber = SerialNumberBuffer;
+ *OutDescriptorLength = Length;
+
+Exit:
+ ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_CreateDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN USB_PORT_STATUS UsbPortStatus,
+ IN ULONG IsWait)
+{
+ ULONG PdoNumber = 0;
+ WCHAR CharDeviceName[64];
+ UNICODE_STRING DeviceName;
+ PDEVICE_OBJECT DeviceObject = NULL;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PUSB_DEVICE_HANDLE DeviceHandle;
+ LPWSTR SerialNumberBuffer;
+ BOOLEAN IsHsDevice;
+ BOOLEAN IsLsDevice;
+ BOOLEAN IgnoringHwSerial = FALSE;
+ NTSTATUS Status;
+ UNICODE_STRING DestinationString;
+
+ DPRINT("USBH_CreateDevice: Port - %x, UsbPortStatus - %lX\n",
+ Port,
+ UsbPortStatus.AsUshort16);
+
+ do
+ {
+ RtlStringCbPrintfW(CharDeviceName,
+ sizeof(CharDeviceName),
+ L"\\Device\\USBPDO-%d",
+ PdoNumber);
+
+ RtlInitUnicodeString(&DeviceName, CharDeviceName);
+
+ Status = IoCreateDevice(HubExtension->Common.SelfDevice->DriverObject,
+ sizeof(USBHUB_PORT_PDO_EXTENSION),
+ &DeviceName,
+ FILE_DEVICE_USB,
+ 0,
+ FALSE,
+ &DeviceObject);
+
+ ++PdoNumber;
+ }
+ while (Status == STATUS_OBJECT_NAME_COLLISION);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(Port > 0);
+ HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
+ return Status;
+ }
+
+ DeviceObject->StackSize = HubExtension->RootHubPdo2->StackSize;
+
+ PortExtension = DeviceObject->DeviceExtension;
+
+ DPRINT("USBH_CreateDevice: PortDevice - %p, <%wZ>\n", DeviceObject, &DeviceName);
+ DPRINT("USBH_CreateDevice: PortExtension - %p\n", PortExtension);
+
+ RtlZeroMemory(PortExtension, sizeof(USBHUB_PORT_PDO_EXTENSION));
+
+ PortExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_PORT;
+ PortExtension->Common.SelfDevice = DeviceObject;
+
+ PortExtension->HubExtension = HubExtension;
+ PortExtension->RootHubExtension = HubExtension;
+
+ PortExtension->PortNumber = Port;
+ PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+ PortExtension->IgnoringHwSerial = FALSE;
+
+ KeInitializeSpinLock(&PortExtension->PortTimeoutSpinLock);
+
+ InitializeListHead(&PortExtension->PortPowerList);
+ KeInitializeSpinLock(&PortExtension->PortPowerListSpinLock);
+
+ PortExtension->PoRequestCounter = 0;
+ PortExtension->PendingSystemPoRequest = 0;
+ PortExtension->PendingDevicePoRequest = 0;
+ PortExtension->StateBehindD2 = 0;
+
+ SerialNumberBuffer = NULL;
+
+ IsHsDevice = UsbPortStatus.Usb20PortStatus.HighSpeedDeviceAttached;
+ IsLsDevice = UsbPortStatus.Usb20PortStatus.LowSpeedDeviceAttached;
+
+ if (IsLsDevice == 0)
+ {
+ if (IsHsDevice)
+ {
+ PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_HIGH_SPEED;
+ }
+ }
+ else
+ {
+ PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_LOW_SPEED;
+ }
+
+ /* Initialize PortExtension->InstanceID */
+ RtlInitUnicodeString(&DestinationString, (PCWSTR)&PortExtension->InstanceID);
+ DestinationString.MaximumLength = 4 * sizeof(WCHAR);
+ Status = RtlIntegerToUnicodeString(Port, 10, &DestinationString);
+
+ DeviceObject->Flags |= DO_POWER_PAGABLE;
+ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_CreateDevice: IoCreateDevice() failed - %lX\n", Status);
+ goto ErrorExit;
+ }
+
+ Status = USBD_CreateDeviceEx(HubExtension,
+ &PortExtension->DeviceHandle,
+ UsbPortStatus,
+ Port);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_CreateDevice: USBD_CreateDeviceEx() failed - %lX\n", Status);
+ goto ErrorExit;
+ }
+
+ Status = USBH_SyncResetPort(HubExtension, Port);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_CreateDevice: USBH_SyncResetPort() failed - %lX\n", Status);
+ goto ErrorExit;
+ }
+
+ if (IsWait)
+ {
+ USBH_Wait(50);
+ }
+
+ Status = USBD_InitializeDeviceEx(HubExtension,
+ PortExtension->DeviceHandle,
+ (PUCHAR)&PortExtension->DeviceDescriptor,
+ sizeof(USB_DEVICE_DESCRIPTOR),
+ (PUCHAR)&PortExtension->ConfigDescriptor,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_CreateDevice: USBD_InitializeDeviceEx() failed - %lX\n", Status);
+ PortExtension->DeviceHandle = NULL;
+ goto ErrorExit;
+ }
+
+ DPRINT1("USBH_RegQueryDeviceIgnoreHWSerNumFlag UNIMPLEMENTED. FIXME\n");
+ //Status = USBH_RegQueryDeviceIgnoreHWSerNumFlag(PortExtension->DeviceDescriptor.idVendor,
+ // PortExtension->DeviceDescriptor.idProduct,
+ // &IgnoringHwSerial);
+
+ if (TRUE)//Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ IgnoringHwSerial = FALSE;
+ }
+
+ if (IgnoringHwSerial)
+ {
+ PortExtension->IgnoringHwSerial = TRUE;
+ }
+
+ if (PortExtension->DeviceDescriptor.iSerialNumber &&
+ !PortExtension->IgnoringHwSerial)
+ {
+ InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber, NULL);
+
+ USBH_GetSerialNumberString(PortExtension->Common.SelfDevice,
+ &SerialNumberBuffer,
+ &PortExtension->SN_DescriptorLength,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ PortExtension->DeviceDescriptor.iSerialNumber);
+
+ if (SerialNumberBuffer)
+ {
+ if (!USBH_ValidateSerialNumberString((PUSHORT)SerialNumberBuffer))
+ {
+ ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
+ SerialNumberBuffer = NULL;
+ }
+
+ if (SerialNumberBuffer &&
+ !USBH_CheckDeviceIDUnique(HubExtension,
+ PortExtension->DeviceDescriptor.idVendor,
+ PortExtension->DeviceDescriptor.idProduct,
+ SerialNumberBuffer,
+ PortExtension->SN_DescriptorLength))
+ {
+ ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
+ SerialNumberBuffer = NULL;
+ }
+ }
+
+ InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
+ SerialNumberBuffer);
+ }
+
+ Status = USBH_ProcessDeviceInformation(PortExtension);
+
+ USBH_PdoSetCapabilities(PortExtension);
+
+ if (NT_SUCCESS(Status))
+ {
+ goto Exit;
+ }
+
+ErrorExit:
+
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INIT_PORT_FAILED;
+
+ DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
+ NULL);
+
+ if (DeviceHandle)
+ {
+ USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
+ }
+
+ SerialNumberBuffer = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
+ NULL);
+
+ if (SerialNumberBuffer)
+ {
+ ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
+ }
+
+Exit:
+
+ ASSERT(Port > 0);
+ HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_ResetDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN BOOLEAN IsKeepDeviceData,
+ IN BOOLEAN IsWait)
+{
+ NTSTATUS Status;
+ PUSBHUB_PORT_DATA PortData;
+ PDEVICE_OBJECT PortDevice;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PVOID NewDeviceHandle;
+ PVOID Handle;
+ PVOID OldDeviceHandle;
+ PUSB_DEVICE_HANDLE * DeviceHandle;
+ USBHUB_PORT_STATUS PortStatus;
+
+ DPRINT("USBH_ResetDevice: HubExtension - %p, Port - %x, IsKeepDeviceData - %x, IsWait - %x\n",
+ HubExtension,
+ Port,
+ IsKeepDeviceData,
+ IsWait);
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if (!NT_SUCCESS(Status) ||
+ !(PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+ KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ASSERT(Port > 0);
+ PortData = &HubExtension->PortData[Port-1];
+
+ PortDevice = PortData->DeviceObject;
+
+ if (!PortDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+
+ KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ return Status;
+ }
+
+ PortExtension = PortDevice->DeviceExtension;
+ DeviceHandle = &PortExtension->DeviceHandle;
+
+ OldDeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
+ NULL);
+
+ if (OldDeviceHandle)
+ {
+ if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOVING_PORT_PDO))
+ {
+ Status = USBD_RemoveDeviceEx(HubExtension,
+ OldDeviceHandle,
+ IsKeepDeviceData);
+
+ PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOVING_PORT_PDO;
+ }
+ }
+ else
+ {
+ OldDeviceHandle = NULL;
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto ErrorExit;
+ }
+
+ Status = USBH_SyncResetPort(HubExtension, Port);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto ErrorExit;
+ }
+
+ Status = USBH_SyncGetPortStatus(HubExtension,
+ Port,
+ &PortStatus,
+ sizeof(USBHUB_PORT_STATUS));
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto ErrorExit;
+ }
+
+ Status = USBD_CreateDeviceEx(HubExtension,
+ DeviceHandle,
+ PortStatus.UsbPortStatus,
+ Port);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto ErrorExit;
+ }
+
+ Status = USBH_SyncResetPort(HubExtension, Port);
+
+ if (IsWait)
+ {
+ USBH_Wait(50);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto ErrorExit;
+ }
+
+ Status = USBD_InitializeDeviceEx(HubExtension,
+ *DeviceHandle,
+ &PortExtension->DeviceDescriptor.bLength,
+ sizeof(PortExtension->DeviceDescriptor),
+ &PortExtension->ConfigDescriptor.bLength,
+ sizeof(PortExtension->ConfigDescriptor));
+
+ if (NT_SUCCESS(Status))
+ {
+ if (IsKeepDeviceData)
+ {
+ Status = USBD_RestoreDeviceEx(HubExtension,
+ OldDeviceHandle,
+ *DeviceHandle);
+
+ if (!NT_SUCCESS(Status))
+ {
+ Handle = InterlockedExchangePointer(DeviceHandle, NULL);
+
+ USBD_RemoveDeviceEx(HubExtension, Handle, 0);
+ USBH_SyncDisablePort(HubExtension, Port);
+
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+ }
+ else
+ {
+ PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOVING_PORT_PDO;
+ }
+
+ goto Exit;
+ }
+
+ *DeviceHandle = NULL;
+
+ErrorExit:
+
+ NewDeviceHandle = InterlockedExchangePointer(DeviceHandle,
+ OldDeviceHandle);
+
+ if (NewDeviceHandle)
+ {
+ Status = USBD_RemoveDeviceEx(HubExtension, NewDeviceHandle, 0);
+ }
+
+Exit:
+
+ KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+ LOW_REALTIME_PRIORITY,
+ 1,
+ FALSE);
+
+ if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+ {
+ KeSetEvent(&HubExtension->PendingRequestEvent,
+ EVENT_INCREMENT,
+ FALSE);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoDispatch(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ UCHAR MajorFunction;
+ BOOLEAN ShouldCompleteIrp;
+ ULONG ControlCode;
+ NTSTATUS Status;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ MajorFunction = IoStack->MajorFunction;
+
+ switch (MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ case IRP_MJ_CLOSE:
+ DPRINT("USBH_PdoDispatch: IRP_MJ_CREATE / IRP_MJ_CLOSE (%d)\n",
+ MajorFunction);
+ Status = STATUS_SUCCESS;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
+ DPRINT("USBH_PdoDispatch: IRP_MJ_DEVICE_CONTROL ControlCode - %x\n",
+ ControlCode);
+
+ if (ControlCode == IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+ }
+
+ if (ControlCode == IOCTL_KS_PROPERTY)
+ {
+ DPRINT1("USBH_PdoDispatch: IOCTL_KS_PROPERTY FIXME\n");
+ DbgBreakPoint();
+ Status = STATUS_NOT_SUPPORTED;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+ }
+
+ Status = Irp->IoStatus.Status;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ Status = USBH_PdoInternalControl(PortExtension, Irp);
+ break;
+
+ case IRP_MJ_PNP:
+ Status = USBH_PdoPnP(PortExtension,
+ Irp,
+ IoStack->MinorFunction,
+ &ShouldCompleteIrp);
+
+ if (ShouldCompleteIrp)
+ {
+ USBH_CompleteIrp(Irp, Status);
+ }
+
+ break;
+
+ case IRP_MJ_POWER:
+ Status = USBH_PdoPower(PortExtension, Irp, IoStack->MinorFunction);
+ break;
+
+ case IRP_MJ_SYSTEM_CONTROL:
+ DPRINT1("USBH_PdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n");
+ Status = STATUS_NOT_SUPPORTED;//USBH_PortSystemControl(PortExtension, Irp);
+ break;
+
+ default:
+ DPRINT("USBH_PdoDispatch: Unhandled MajorFunction - %d\n", MajorFunction);
+ Status = Irp->IoStatus.Status;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoDispatch(IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ UCHAR MajorFunction;
+ NTSTATUS Status;
+
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ DPRINT("USBH_FdoDispatch: HubExtension - %p, Irp - %p, MajorFunction - %X\n",
+ HubExtension,
+ Irp,
+ IoStack->MajorFunction);
+
+ MajorFunction = IoStack->MajorFunction;
+
+ switch (MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ case IRP_MJ_CLOSE:
+ Status = STATUS_SUCCESS;
+ USBH_CompleteIrp(Irp, Status);
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = USBH_DeviceControl(HubExtension, Irp);
+ break;
+
+ case IRP_MJ_PNP:
+ Status = USBH_FdoPnP(HubExtension, Irp, IoStack->MinorFunction);
+ break;
+
+ case IRP_MJ_POWER:
+ Status = USBH_FdoPower(HubExtension, Irp, IoStack->MinorFunction);
+ break;
+
+ case IRP_MJ_SYSTEM_CONTROL:
+ DPRINT1("USBH_FdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n");
+ /* fall through */
+
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+ default:
+ Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+ break;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_AddDevice(IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT LowerPDO)
+{
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PDEVICE_OBJECT LowerDevice;
+
+ DPRINT("USBH_AddDevice: DriverObject - %p, LowerPDO - %p\n",
+ DriverObject,
+ LowerPDO);
+
+ DeviceObject = NULL;
+
+ Status = IoCreateDevice(DriverObject,
+ sizeof(USBHUB_FDO_EXTENSION),
+ NULL,
+ 0x8600,
+ FILE_AUTOGENERATED_DEVICE_NAME,
+ FALSE,
+ &DeviceObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("USBH_AddDevice: IoCreateDevice() fail\n");
+
+ if (DeviceObject)
+ {
+ IoDeleteDevice(DeviceObject);
+ }
+
+ return Status;
+ }
+
+ DPRINT("USBH_AddDevice: DeviceObject - %p\n", DeviceObject);
+
+ HubExtension = DeviceObject->DeviceExtension;
+ RtlZeroMemory(HubExtension, sizeof(USBHUB_FDO_EXTENSION));
+
+ HubExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_HUB;
+
+ LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, LowerPDO);
+
+ if (!LowerDevice)
+ {
+ DPRINT1("USBH_AddDevice: IoAttachDeviceToDeviceStack() fail\n");
+
+ if (DeviceObject)
+ {
+ IoDeleteDevice(DeviceObject);
+ }
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ DPRINT("USBH_AddDevice: LowerDevice - %p\n", LowerDevice);
+
+ HubExtension->Common.SelfDevice = DeviceObject;
+
+ HubExtension->LowerPDO = LowerPDO;
+ HubExtension->LowerDevice = LowerDevice;
+
+ KeInitializeSemaphore(&HubExtension->IdleSemaphore, 1, 1);
+
+ DeviceObject->Flags |= DO_POWER_PAGABLE;
+ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ DPRINT("USBH_AddDevice: call IoWMIRegistrationControl() UNIMPLEMENTED. FIXME\n");
+
+ return Status;
+}
+
+VOID
+NTAPI
+USBH_DriverUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ DPRINT("USBH_DriverUnload: UNIMPLEMENTED\n");
+
+ if (GenericUSBDeviceString)
+ {
+ ExFreePool(GenericUSBDeviceString);
+ GenericUSBDeviceString = NULL;
+ }
+}
+
+NTSTATUS
+NTAPI
+USBH_HubDispatch(IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PCOMMON_DEVICE_EXTENSION DeviceExtension;
+ ULONG ExtensionType;
+ NTSTATUS Status;
+
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ ExtensionType = DeviceExtension->ExtensionType;
+
+ if (ExtensionType == USBH_EXTENSION_TYPE_HUB)
+ {
+ DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+
+ Status = USBH_FdoDispatch((PUSBHUB_FDO_EXTENSION)DeviceExtension, Irp);
+ }
+ else if (ExtensionType == USBH_EXTENSION_TYPE_PORT)
+ {
+ PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
+ UCHAR MajorFunction = IoStack->MajorFunction;
+ BOOLEAN IsDprint = TRUE;
+
+ if (MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
+ {
+ ULONG ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
+
+ if (ControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
+ {
+ IsDprint = FALSE;
+ }
+ }
+
+ if (IsDprint)
+ {
+ DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n",
+ DeviceObject,
+ Irp);
+ }
+
+ Status = USBH_PdoDispatch((PUSBHUB_PORT_PDO_EXTENSION)DeviceExtension, Irp);
+ }
+ else
+ {
+ DPRINT1("USBH_HubDispatch: Unknown ExtensionType - %x\n", ExtensionType);
+ DbgBreakPoint();
+ Status = STATUS_ASSERTION_FAILURE;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_RegQueryGenericUSBDeviceString(PVOID USBDeviceString)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+ DPRINT("USBH_RegQueryGenericUSBDeviceString ... \n");
+
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
+
+ QueryTable[0].QueryRoutine = USBH_GetConfigValue;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = L"GenericUSBDeviceString";
+ QueryTable[0].EntryContext = USBDeviceString;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = 0;
+ QueryTable[0].DefaultLength = 0;
+
+ return RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+ L"usbflags",
+ QueryTable,
+ NULL,
+ NULL);
+}
+
+NTSTATUS
+NTAPI
+DriverEntry(IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ DPRINT("USBHUB: DriverEntry - %wZ\n", RegistryPath);
+
+ DriverObject->DriverExtension->AddDevice = USBH_AddDevice;
+ DriverObject->DriverUnload = USBH_DriverUnload;
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = USBH_HubDispatch;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBH_HubDispatch;
+
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBH_HubDispatch;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBH_HubDispatch;
+
+ DriverObject->MajorFunction[IRP_MJ_PNP] = USBH_HubDispatch;
+ DriverObject->MajorFunction[IRP_MJ_POWER] = USBH_HubDispatch;
+ DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBH_HubDispatch;
+
+ USBH_RegQueryGenericUSBDeviceString(&GenericUSBDeviceString);
+
+ return STATUS_SUCCESS;
+}
+
--- /dev/null
+#ifndef _USBHUB_H_
+#define _USBHUB_H_
+
+#include <ntddk.h>
+#include <windef.h>
+#include <stdio.h>
+#include <wmistr.h>
+#include <wmilib.h>
+#include <wdmguid.h>
+#include <ntstrsafe.h>
+#include <usb.h>
+#include <usbioctl.h>
+#include <hubbusif.h>
+#include <usbbusif.h>
+#include <usbdlib.h>
+#include <ks.h>
+#include <drivers/usbport/usbmport.h>
+
+#define USB_HUB_TAG 'BUHU'
+
+#define USBH_EXTENSION_TYPE_HUB 0x01
+#define USBH_EXTENSION_TYPE_PORT 0x02
+#define USBH_EXTENSION_TYPE_PARENT 0x04
+#define USBH_EXTENSION_TYPE_FUNCTION 0x08
+
+#define USBHUB_FDO_FLAG_DEVICE_STARTED (1 << 0)
+#define USBHUB_FDO_FLAG_DEVICE_STOPPING (1 << 2)
+#define USBHUB_FDO_FLAG_DEVICE_FAILED (1 << 3)
+#define USBHUB_FDO_FLAG_REMOTE_WAKEUP (1 << 4)
+#define USBHUB_FDO_FLAG_DEVICE_STOPPED (1 << 5)
+#define USBHUB_FDO_FLAG_HUB_BUSY (1 << 6)
+#define USBHUB_FDO_FLAG_PENDING_WAKE_IRP (1 << 7)
+#define USBHUB_FDO_FLAG_RESET_PORT_LOCK (1 << 8)
+#define USBHUB_FDO_FLAG_ESD_RECOVERING (1 << 9)
+#define USBHUB_FDO_FLAG_SET_D0_STATE (1 << 10)
+#define USBHUB_FDO_FLAG_NOT_D0_STATE (1 << 11)
+#define USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST (1 << 12)
+#define USBHUB_FDO_FLAG_STATE_CHANGING (1 << 13)
+#define USBHUB_FDO_FLAG_DEVICE_REMOVED (1 << 14)
+#define USBHUB_FDO_FLAG_USB20_HUB (1 << 15)
+#define USBHUB_FDO_FLAG_DEFER_CHECK_IDLE (1 << 16)
+#define USBHUB_FDO_FLAG_WAKEUP_START (1 << 17)
+#define USBHUB_FDO_FLAG_MULTIPLE_TTS (1 << 18) // High-speed Operating Hub with Multiple TTs
+#define USBHUB_FDO_FLAG_ENUM_POST_RECOVER (1 << 19)
+#define USBHUB_FDO_FLAG_DO_ENUMERATION (1 << 20)
+#define USBHUB_FDO_FLAG_CHECK_IDLE_LOCK (1 << 21)
+#define USBHUB_FDO_FLAG_HIBERNATE_STATE (1 << 22)
+#define USBHUB_FDO_FLAG_NOT_ENUMERATED (1 << 23)
+#define USBHUB_FDO_FLAG_DO_SUSPENSE (1 << 24)
+#define USBHUB_FDO_FLAG_GOING_IDLE (1 << 25)
+#define USBHUB_FDO_FLAG_DEVICE_SUSPENDED (1 << 26)
+#define USBHUB_FDO_FLAG_WITEM_INIT (1 << 27)
+
+#define USBHUB_PDO_FLAG_HUB_DEVICE (1 << 0)
+#define USBHUB_PDO_FLAG_MULTI_INTERFACE (1 << 1)
+#define USBHUB_PDO_FLAG_INIT_PORT_FAILED (1 << 2)
+#define USBHUB_PDO_FLAG_PORT_LOW_SPEED (1 << 3)
+#define USBHUB_PDO_FLAG_REMOTE_WAKEUP (1 << 4)
+#define USBHUB_PDO_FLAG_WAIT_WAKE (1 << 5)
+#define USBHUB_PDO_FLAG_NOT_CONNECTED (1 << 6)
+#define USBHUB_PDO_FLAG_DELETE_PENDING (1 << 7)
+#define USBHUB_PDO_FLAG_POWER_D3 (1 << 8)
+#define USBHUB_PDO_FLAG_DEVICE_STARTED (1 << 9)
+#define USBHUB_PDO_FLAG_HS_USB1_DUALMODE (1 << 10)
+#define USBHUB_PDO_FLAG_REG_DEV_INTERFACE (1 << 11) // SymbolicLink
+#define USBHUB_PDO_FLAG_PORT_RESTORE_FAIL (1 << 12)
+#define USBHUB_PDO_FLAG_POWER_D1_OR_D2 (1 << 13)
+#define USBHUB_PDO_FLAG_OVERCURRENT_PORT (1 << 14)
+#define USBHUB_PDO_FLAG_REMOVING_PORT_PDO (1 << 15)
+#define USBHUB_PDO_FLAG_INSUFFICIENT_PWR (1 << 16)
+#define USBHUB_PDO_FLAG_ALLOC_BNDW_FAILED (1 << 18)
+#define USBHUB_PDO_FLAG_PORT_RESSETING (1 << 19)
+#define USBHUB_PDO_FLAG_IDLE_NOTIFICATION (1 << 22)
+#define USBHUB_PDO_FLAG_PORT_HIGH_SPEED (1 << 23)
+#define USBHUB_PDO_FLAG_ENUMERATED (1 << 26)
+
+#define USBHUB_ENUM_FLAG_DEVICE_PRESENT 0x01
+#define USBHUB_ENUM_FLAG_GHOST_DEVICE 0x02
+
+/* Hub Class Feature Selectors */
+#define USBHUB_FEATURE_USBHUB_FEATURE_C_HUB_LOCAL_POWER 0
+#define USBHUB_FEATURE_C_HUB_OVER_CURRENT 1
+
+#define USBHUB_FEATURE_PORT_CONNECTION 0
+#define USBHUB_FEATURE_PORT_ENABLE 1
+#define USBHUB_FEATURE_PORT_SUSPEND 2
+#define USBHUB_FEATURE_PORT_OVER_CURRENT 3
+#define USBHUB_FEATURE_PORT_RESET 4
+#define USBHUB_FEATURE_PORT_POWER 8
+#define USBHUB_FEATURE_PORT_LOW_SPEED 9
+#define USBHUB_FEATURE_C_PORT_CONNECTION 16
+#define USBHUB_FEATURE_C_PORT_ENABLE 17
+#define USBHUB_FEATURE_C_PORT_SUSPEND 18
+#define USBHUB_FEATURE_C_PORT_OVER_CURRENT 19
+#define USBHUB_FEATURE_C_PORT_RESET 20
+#define USBHUB_FEATURE_PORT_TEST 21
+#define USBHUB_FEATURE_PORT_INDICATOR 22
+
+#define USBHUB_MAX_CASCADE_LEVELS 6
+#define USBHUB_RESET_PORT_MAX_RETRY 3
+#define USBHUB_MAX_REQUEST_ERRORS 3
+
+
+#define USBHUB_FAIL_NO_FAIL 5
+#define USBHUB_FAIL_NESTED_TOO_DEEPLY 6
+#define USBHUB_FAIL_OVERCURRENT 7
+
+extern PWSTR GenericUSBDeviceString;
+
+typedef struct _USBHUB_PORT_DATA {
+ USBHUB_PORT_STATUS PortStatus;
+ PDEVICE_OBJECT DeviceObject;
+ USB_CONNECTION_STATUS ConnectionStatus;
+ ULONG PortAttributes;
+} USBHUB_PORT_DATA, *PUSBHUB_PORT_DATA;
+
+typedef struct _USBHUB_FDO_EXTENSION *PUSBHUB_FDO_EXTENSION;
+
+typedef VOID
+(NTAPI * PUSBHUB_WORKER_ROUTINE)(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context);
+
+typedef struct _USBHUB_IO_WORK_ITEM {
+ ULONG Reserved;
+ LIST_ENTRY HubWorkItemLink;
+ LONG HubWorkerQueued;
+ PIO_WORKITEM HubWorkItem;
+ WORK_QUEUE_TYPE HubWorkItemType;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PUSBHUB_WORKER_ROUTINE HubWorkerRoutine;
+ PVOID HubWorkItemBuffer;
+} USBHUB_IO_WORK_ITEM, *PUSBHUB_IO_WORK_ITEM;
+
+typedef struct _COMMON_DEVICE_EXTENSION {
+ ULONG ExtensionType;
+ PDEVICE_OBJECT SelfDevice;
+} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
+
+typedef struct _USBHUB_FDO_EXTENSION {
+ COMMON_DEVICE_EXTENSION Common;
+ PDEVICE_OBJECT LowerPDO;
+ PDEVICE_OBJECT LowerDevice;
+ PDEVICE_OBJECT RootHubPdo;
+ PDEVICE_OBJECT RootHubPdo2;
+ KEVENT LowerDeviceEvent;
+ ULONG HubFlags;
+ USB_BUS_INTERFACE_HUB_V5 BusInterface;
+ USB_BUS_INTERFACE_USBDI_V2 BusInterfaceUSBDI;
+ DEVICE_POWER_STATE DeviceState[POWER_SYSTEM_MAXIMUM];
+ SYSTEM_POWER_STATE SystemWake;
+ DEVICE_POWER_STATE DeviceWake;
+ POWER_STATE CurrentPowerState;
+ POWER_STATE SystemPowerState;
+ ULONG MaxPowerPerPort;
+ USB_DEVICE_DESCRIPTOR HubDeviceDescriptor;
+ USHORT Port;
+ PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor;
+ PUSB_HUB_DESCRIPTOR HubDescriptor;
+ PUSBHUB_PORT_DATA PortData;
+ USBD_CONFIGURATION_HANDLE ConfigHandle;
+ USBD_PIPE_INFORMATION PipeInfo;
+ PIRP SCEIrp;
+ PIRP ResetPortIrp;
+ PVOID SCEBitmap; // 11.12.4 Hub and Port Status Change Bitmap (USB 2.0 Specification)
+ ULONG SCEBitmapLength;
+ KEVENT RootHubNotificationEvent;
+ struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST SCEWorkerUrb;
+ KEVENT StatusChangeEvent;
+ KSEMAPHORE IdleSemaphore;
+ KSPIN_LOCK RelationsWorkerSpinLock;
+ LIST_ENTRY PdoList;
+ LONG PendingRequestCount;
+ KEVENT PendingRequestEvent;
+ KSEMAPHORE ResetDeviceSemaphore;
+ PRKEVENT pResetPortEvent;
+ KSEMAPHORE HubPortSemaphore;
+ LONG ResetRequestCount;
+ KEVENT ResetEvent;
+ PIRP PendingIdleIrp;
+ PIRP PendingWakeIrp;
+ LONG FdoWaitWakeLock;
+ LIST_ENTRY WorkItemList;
+ KSPIN_LOCK WorkItemSpinLock;
+ KSPIN_LOCK CheckIdleSpinLock;
+ KEVENT IdleEvent;
+ LONG IdleRequestLock;
+ ULONG RequestErrors;
+ KSEMAPHORE HubSemaphore;
+ PUSBHUB_IO_WORK_ITEM WorkItemToQueue;
+ USB_IDLE_CALLBACK_INFO IdleCallbackInfo;
+ USBHUB_PORT_STATUS PortStatus;
+ PIRP PowerIrp;
+} USBHUB_FDO_EXTENSION, *PUSBHUB_FDO_EXTENSION;
+
+typedef struct _USBHUB_PORT_PDO_EXTENSION {
+ COMMON_DEVICE_EXTENSION Common;
+ ULONG PortPdoFlags;
+ ULONG EnumFlags;
+ UNICODE_STRING SymbolicLinkName;
+ WCHAR InstanceID[4];
+ PUSBHUB_FDO_EXTENSION HubExtension;
+ PUSBHUB_FDO_EXTENSION RootHubExtension;
+ PUSB_DEVICE_HANDLE DeviceHandle;
+ USHORT PortNumber;
+ USHORT SN_DescriptorLength;
+ BOOL IgnoringHwSerial;
+ LPWSTR SerialNumber; // serial number string
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ USB_DEVICE_DESCRIPTOR OldDeviceDescriptor;
+ USB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+ USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ USHORT Reserved1;
+ PIRP IdleNotificationIrp;
+ POWER_STATE CurrentPowerState;
+ DEVICE_CAPABILITIES Capabilities;
+ ULONG MaxPower;
+ PVOID BndwTimeoutContext;
+ KSPIN_LOCK PortTimeoutSpinLock;
+ LIST_ENTRY PortLink;
+ LONG PoRequestCounter;
+ LONG PendingSystemPoRequest;
+ LONG PendingDevicePoRequest;
+ LONG StateBehindD2;
+ PIRP PdoWaitWakeIrp;
+ LIST_ENTRY PortPowerList;
+ KSPIN_LOCK PortPowerListSpinLock;
+} USBHUB_PORT_PDO_EXTENSION, *PUSBHUB_PORT_PDO_EXTENSION;
+
+typedef struct _USBHUB_URB_TIMEOUT_CONTEXT {
+ PIRP Irp;
+ KEVENT UrbTimeoutEvent;
+ KDPC UrbTimeoutDPC;
+ KTIMER UrbTimeoutTimer;
+ KSPIN_LOCK UrbTimeoutSpinLock;
+ BOOL IsNormalCompleted;
+} USBHUB_URB_TIMEOUT_CONTEXT, *PUSBHUB_URB_TIMEOUT_CONTEXT;
+
+typedef struct _USBHUB_STATUS_CHANGE_CONTEXT {
+ ULONG Reserved;
+ BOOL IsRequestErrors;
+ PUSBHUB_FDO_EXTENSION HubExtension;
+} USBHUB_STATUS_CHANGE_CONTEXT, *PUSBHUB_STATUS_CHANGE_CONTEXT;
+
+typedef struct _USBHUB_IDLE_HUB_CONTEXT {
+ ULONG Reserved;
+ NTSTATUS Status;
+} USBHUB_IDLE_HUB_CONTEXT, *PUSBHUB_IDLE_HUB_CONTEXT;
+
+typedef struct _USBHUB_IDLE_PORT_CONTEXT {
+ ULONG Reserved;
+ LIST_ENTRY PwrList;
+ NTSTATUS Status;
+} USBHUB_IDLE_PORT_CONTEXT, *PUSBHUB_IDLE_PORT_CONTEXT;
+
+typedef struct _USBHUB_IDLE_PORT_CANCEL_CONTEXT {
+ ULONG Reserved;
+ PIRP Irp;
+} USBHUB_IDLE_PORT_CANCEL_CONTEXT, *PUSBHUB_IDLE_PORT_CANCEL_CONTEXT;
+
+typedef struct _USBHUB_RESET_PORT_CONTEXT {
+ ULONG Reserved;
+ PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+ PIRP Irp;
+} USBHUB_RESET_PORT_CONTEXT, *PUSBHUB_RESET_PORT_CONTEXT;
+
+/* debug.c */
+VOID
+NTAPI
+USBHUB_DumpingDeviceDescriptor(
+ IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor);
+
+VOID
+NTAPI
+USBHUB_DumpingConfiguration(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor);
+
+VOID
+NTAPI
+USBHUB_DumpingIDs(
+ IN PVOID Id);
+
+/* ioctl.c */
+NTSTATUS
+NTAPI
+USBH_DeviceControl(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp);
+
+NTSTATUS
+NTAPI
+USBH_PdoInternalControl(
+ IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp);
+
+/* pnp.c */
+NTSTATUS
+NTAPI
+USBH_PdoRemoveDevice(
+ IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBH_FdoPnP(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor);
+
+NTSTATUS
+NTAPI
+USBH_PdoPnP(
+ IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor,
+ OUT BOOLEAN * IsCompleteIrp);
+
+/* power.c */
+VOID
+NTAPI
+USBH_CompletePowerIrp(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN NTSTATUS NtStatus);
+
+NTSTATUS
+NTAPI
+USBH_HubSetD0(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBH_FdoPower(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor);
+
+NTSTATUS
+NTAPI
+USBH_PdoPower(
+ IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PIRP Irp,
+ IN UCHAR Minor);
+
+VOID
+NTAPI
+USBH_HubCompletePortWakeIrps(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN NTSTATUS NtStatus);
+
+VOID
+NTAPI
+USBH_HubCancelWakeIrp(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP Irp);
+
+VOID
+NTAPI
+USBH_IdleCancelPowerHubWorker(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PVOID Context);
+
+/* usbhub.c */
+NTSTATUS
+NTAPI
+USBH_Wait(
+ IN ULONG Milliseconds);
+
+VOID
+NTAPI
+USBH_CompleteIrp(
+ IN PIRP Irp,
+ IN NTSTATUS CompleteStatus);
+
+NTSTATUS
+NTAPI
+USBH_PassIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+PUSBHUB_PORT_PDO_EXTENSION
+NTAPI
+PdoExt(
+ IN PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS
+NTAPI
+USBH_WriteFailReasonID(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG Data);
+
+NTSTATUS
+NTAPI
+USBH_SetPdoRegistryParameter(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PCWSTR SourceString,
+ IN PVOID Data,
+ IN ULONG DataSize,
+ IN ULONG Type,
+ IN ULONG DevInstKeyType);
+
+NTSTATUS
+NTAPI
+USBH_SyncSubmitUrb(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PURB Urb);
+
+NTSTATUS
+NTAPI
+USBH_FdoSyncSubmitUrb(
+ IN PDEVICE_OBJECT FdoDevice,
+ IN PURB Urb);
+
+NTSTATUS
+NTAPI
+USBH_SyncResetPort(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port);
+
+NTSTATUS
+NTAPI
+USBH_GetDeviceType(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE DeviceHandle,
+ OUT USB_DEVICE_TYPE * OutDeviceType);
+
+PUSBHUB_FDO_EXTENSION
+NTAPI
+USBH_GetRootHubExtension(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBH_SyncGetRootHubPdo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PDEVICE_OBJECT * OutPdo1,
+ IN OUT PDEVICE_OBJECT * OutPdo2);
+
+NTSTATUS
+NTAPI
+USBH_SyncGetHubCount(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PULONG OutHubCount);
+
+PUSB_DEVICE_HANDLE
+NTAPI
+USBH_SyncGetDeviceHandle(
+ IN PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS
+NTAPI
+USBH_GetDeviceDescriptor(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor);
+
+NTSTATUS
+NTAPI
+USBH_GetConfigurationDescriptor(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_CONFIGURATION_DESCRIPTOR * pConfigurationDescriptor);
+
+NTSTATUS
+NTAPI
+USBH_SyncGetHubDescriptor(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBH_SyncGetStringDescriptor(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR Index,
+ IN USHORT LanguageId,
+ IN PUSB_STRING_DESCRIPTOR Descriptor,
+ IN ULONG NumberOfBytes,
+ IN PULONG OutLength,
+ IN BOOLEAN IsValidateLength);
+
+NTSTATUS
+NTAPI
+USBH_SyncGetPortStatus(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN PUSBHUB_PORT_STATUS PortStatus,
+ IN ULONG Length);
+
+NTSTATUS
+NTAPI
+USBH_SyncClearPortStatus(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN USHORT RequestValue);
+
+NTSTATUS
+NTAPI
+USBH_SyncPowerOnPorts(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBH_SyncDisablePort(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port);
+
+BOOLEAN
+NTAPI
+USBH_HubIsBusPowered(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor);
+
+NTSTATUS
+NTAPI
+USBH_SubmitStatusChangeTransfer(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBD_CreateDeviceEx(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE * OutDeviceHandle,
+ IN USB_PORT_STATUS UsbPortStatus,
+ IN USHORT Port);
+
+NTSTATUS
+NTAPI
+USBD_RemoveDeviceEx(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE DeviceHandle,
+ IN ULONG Flags);
+
+NTSTATUS
+NTAPI
+USBD_InitializeDeviceEx(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_DEVICE_HANDLE DeviceHandle,
+ IN PUCHAR DeviceDescriptorBuffer,
+ IN ULONG DeviceDescriptorBufferLength,
+ IN PUCHAR ConfigDescriptorBuffer,
+ IN ULONG ConfigDescriptorBufferLength);
+
+VOID
+NTAPI
+USBHUB_SetDeviceHandleData(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PDEVICE_OBJECT UsbDevicePdo,
+ IN PVOID DeviceHandle);
+
+VOID
+NTAPI
+USBHUB_FlushAllTransfers(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBD_GetDeviceInformationEx(
+ IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,
+ IN ULONG Length,
+ IN PUSB_DEVICE_HANDLE DeviceHandle);
+
+NTSTATUS
+NTAPI
+USBD_RestoreDeviceEx(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
+ IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle);
+
+NTSTATUS
+NTAPI
+USBH_AllocateWorkItem(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ OUT PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,
+ IN PUSBHUB_WORKER_ROUTINE WorkerRoutine,
+ IN SIZE_T BufferLength,
+ OUT PVOID * OutHubWorkItemBuffer,
+ IN WORK_QUEUE_TYPE Type);
+
+VOID
+NTAPI
+USBH_QueueWorkItem(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem);
+
+VOID
+NTAPI
+USBH_FreeWorkItem(
+ IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem);
+
+NTSTATUS
+NTAPI
+USBD_RegisterRootHubCallBack(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBD_UnRegisterRootHubCallBack(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+VOID
+NTAPI
+USBH_HubCancelIdleIrp(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN PIRP IdleIrp);
+
+BOOLEAN
+NTAPI
+USBH_CheckIdleAbort(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN BOOLEAN IsWait,
+ IN BOOLEAN IsExtCheck);
+
+VOID
+NTAPI
+USBH_CheckHubIdle(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+VOID
+NTAPI
+USBH_CheckIdleDeferred(
+ IN PUSBHUB_FDO_EXTENSION HubExtension);
+
+NTSTATUS
+NTAPI
+USBH_CheckDeviceLanguage(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN USHORT LanguageId);
+
+NTSTATUS
+NTAPI
+USBH_CreateDevice(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN USB_PORT_STATUS UsbPortStatus,
+ IN ULONG IsWait);
+
+NTSTATUS
+NTAPI
+USBH_ResetDevice(
+ IN PUSBHUB_FDO_EXTENSION HubExtension,
+ IN USHORT Port,
+ IN BOOLEAN IsKeepDeviceData,
+ IN BOOLEAN IsWait);
+
+NTSTATUS
+NTAPI
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
+
+#endif /* _USBHUB_H_ */
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "Hub Driver for USB"
+#define REACTOS_STR_INTERNAL_NAME "usbhub"
+#define REACTOS_STR_ORIGINAL_FILENAME "usbhub.sys"
+#include <reactos/version.rc>