From dc50f1da19c4ed609bd731423e19628f6727ec10 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Wed, 28 Jun 2017 23:23:01 +0000 Subject: [PATCH] [USBHUB_NEW] Bring-in the USB Hub driver created by Vadim Galyant. GitHub PR #29. As usual, I thank the code reviewers, especially Thomas for contributing most of the reviews, improvements and fix suggestions. svn path=/trunk/; revision=75227 --- reactos/drivers/usb/CMakeLists.txt | 1 + reactos/drivers/usb/usbhub_new/CMakeLists.txt | 22 + reactos/drivers/usb/usbhub_new/dbg_uhub.h | 109 + reactos/drivers/usb/usbhub_new/debug.c | 125 + reactos/drivers/usb/usbhub_new/guid.c | 11 + reactos/drivers/usb/usbhub_new/ioctl.c | 1408 +++++ reactos/drivers/usb/usbhub_new/pnp.c | 2811 +++++++++ reactos/drivers/usb/usbhub_new/power.c | 794 +++ reactos/drivers/usb/usbhub_new/usbhub.c | 5047 +++++++++++++++++ reactos/drivers/usb/usbhub_new/usbhub.h | 650 +++ reactos/drivers/usb/usbhub_new/usbhub.rc | 5 + 11 files changed, 10983 insertions(+) create mode 100644 reactos/drivers/usb/usbhub_new/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbhub_new/dbg_uhub.h create mode 100644 reactos/drivers/usb/usbhub_new/debug.c create mode 100644 reactos/drivers/usb/usbhub_new/guid.c create mode 100644 reactos/drivers/usb/usbhub_new/ioctl.c create mode 100644 reactos/drivers/usb/usbhub_new/pnp.c create mode 100644 reactos/drivers/usb/usbhub_new/power.c create mode 100644 reactos/drivers/usb/usbhub_new/usbhub.c create mode 100644 reactos/drivers/usb/usbhub_new/usbhub.h create mode 100644 reactos/drivers/usb/usbhub_new/usbhub.rc diff --git a/reactos/drivers/usb/CMakeLists.txt b/reactos/drivers/usb/CMakeLists.txt index d8e07f9d1ad..d47a55cc821 100644 --- a/reactos/drivers/usb/CMakeLists.txt +++ b/reactos/drivers/usb/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(usbccgp) add_subdirectory(usbd) add_subdirectory(usbehci) add_subdirectory(usbhub) +#add_subdirectory(usbhub_new) add_subdirectory(usbohci) add_subdirectory(usbport) add_subdirectory(usbstor) diff --git a/reactos/drivers/usb/usbhub_new/CMakeLists.txt b/reactos/drivers/usb/usbhub_new/CMakeLists.txt new file mode 100644 index 00000000000..a1355dfa500 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/CMakeLists.txt @@ -0,0 +1,22 @@ + +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) diff --git a/reactos/drivers/usb/usbhub_new/dbg_uhub.h b/reactos/drivers/usb/usbhub_new/dbg_uhub.h new file mode 100644 index 00000000000..03c18c1b60d --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/dbg_uhub.h @@ -0,0 +1,109 @@ +#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__ */ diff --git a/reactos/drivers/usb/usbhub_new/debug.c b/reactos/drivers/usb/usbhub_new/debug.c new file mode 100644 index 00000000000..d0b4039f6f3 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/debug.c @@ -0,0 +1,125 @@ +#include "usbhub.h" + +//#define NDEBUG +#include + +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"); +} diff --git a/reactos/drivers/usb/usbhub_new/guid.c b/reactos/drivers/usb/usbhub_new/guid.c new file mode 100644 index 00000000000..b6cc0a3140f --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/guid.c @@ -0,0 +1,11 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include +#include +#include +#include +#include +#include +#include + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/reactos/drivers/usb/usbhub_new/ioctl.c b/reactos/drivers/usb/usbhub_new/ioctl.c new file mode 100644 index 00000000000..fd99604f477 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/ioctl.c @@ -0,0 +1,1408 @@ +#include "usbhub.h" + +#define NDEBUG +#include + +#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; +} diff --git a/reactos/drivers/usb/usbhub_new/pnp.c b/reactos/drivers/usb/usbhub_new/pnp.c new file mode 100644 index 00000000000..bfdd8e195a1 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/pnp.c @@ -0,0 +1,2811 @@ +#include "usbhub.h" + +#define NDEBUG +#include + +#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; +} diff --git a/reactos/drivers/usb/usbhub_new/power.c b/reactos/drivers/usb/usbhub_new/power.c new file mode 100644 index 00000000000..172e709657b --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/power.c @@ -0,0 +1,794 @@ +#include "usbhub.h" + +#define NDEBUG +#include + +#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; +} diff --git a/reactos/drivers/usb/usbhub_new/usbhub.c b/reactos/drivers/usb/usbhub_new/usbhub.c new file mode 100644 index 00000000000..6f3ea0656ba --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/usbhub.c @@ -0,0 +1,5047 @@ +#include "usbhub.h" + +#define NDEBUG +#include + +#define NDEBUG_USBHUB_SCE +#define NDEBUG_USBHUB_PNP +#include "dbg_uhub.h" + +#include + +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; +} + diff --git a/reactos/drivers/usb/usbhub_new/usbhub.h b/reactos/drivers/usb/usbhub_new/usbhub.h new file mode 100644 index 00000000000..3bdefbd73f5 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/usbhub.h @@ -0,0 +1,650 @@ +#ifndef _USBHUB_H_ +#define _USBHUB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_ */ diff --git a/reactos/drivers/usb/usbhub_new/usbhub.rc b/reactos/drivers/usb/usbhub_new/usbhub.rc new file mode 100644 index 00000000000..e5d995562ce --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/usbhub.rc @@ -0,0 +1,5 @@ +#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